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.

6860 vulnerabilities reference this CWE, most recent first.

GHSA-V833-3823-CMHP

Vulnerability from github – Published: 2026-07-31 16:27 – Updated: 2026-07-31 16:27
VLAI
Summary
OnionShare Receive mode writes uploaded files even when file uploads are disabled
Details

Summary

OnionShare CLI/Desktop 2.6.3 does not enforce the Receive mode disable_files setting at the file upload sink. When a Receive service is configured as a text-message-only endpoint (--disable-files / "Disable uploading files"), a remote sender who can reach the OnionShare service can still send a crafted multipart request containing file[]; OnionShare writes the uploaded bytes to disk before the route handler skips file accounting.

This affects the shipped onionshare-cli Python package and the desktop application because both use the same onionshare_cli.web.receive_mode request-streaming implementation.

Details

Tested repository: https://github.com/onionshare/onionshare at commit 8cc75e1d7e88bd31f7276733449d412bf71c8999.

Affected product evidence: - cli/pyproject.toml declares onionshare_cli version 2.6.3. - desktop/pyproject.toml declares onionshare version 2.6.3 and depends on onionshare_cli from ../cli. - cli/setup.py publishes onionshare-cli and includes onionshare_cli.web plus templates/static resources. - desktop/setup.py publishes onionshare and exposes both onionshare and onionshare-cli console scripts.

Reachable default/common paths: - CLI Receive mode is exposed through --receive (cli/onionshare_cli/__init__.py:55-57). - The --disable-files option is documented and stored in mode settings (cli/onionshare_cli/__init__.py:156-160, cli/onionshare_cli/__init__.py:254-261). - Desktop Receive mode exposes the same setting via the "Disable uploading files" checkbox and stores it as receive.disable_files (desktop/onionshare/tab/mode/receive_mode/__init__.py:89-99, desktop/onionshare/tab/mode/receive_mode/__init__.py:246-254). - User documentation says "Disable uploading files" should "only allow submitting text messages, like for an anonymous contact form" (docs/source/features.rst:64). - Advanced documentation lists --disable-files and disable_files as the option to disable receiving files (docs/source/advanced.rst:162-163, docs/source/advanced.rst:455).

Root cause: - The Receive template hides the file input when disable_files is set (cli/onionshare_cli/resources/templates/receive.html:51-56), but this is only UI-side. - The /upload route skips request.files.getlist("file[]") and file accounting when disable_files is enabled (cli/onionshare_cli/web/receive_mode.py:96-135). However, by this point Werkzeug has already parsed the multipart body and invoked the custom stream factory. - ReceiveModeRequest.__init__() treats every POST /upload or POST /upload-ajax as an upload request and creates a receive directory regardless of disable_files (cli/onionshare_cli/web/receive_mode.py:369-391). - ReceiveModeRequest._get_file_stream() creates a writable ReceiveModeFile for each uploaded part without checking self.web.settings.get("receive", "disable_files") (cli/onionshare_cli/web/receive_mode.py:517-540). - ReceiveModeFile opens <receive_mode_dir>/<secure_filename>.part, writes attacker-controlled bytes, then renames the .part file to the final filename (cli/onionshare_cli/web/receive_mode.py:272-285, cli/onionshare_cli/web/receive_mode.py:320-346).

False-positive screening performed: - secure_filename() is used at cli/onionshare_cli/web/receive_mode.py:111-113 and cli/onionshare_cli/web/receive_mode.py:527-528, so the confirmed issue is not path traversal; the file is written under the configured receive data directory. - The UI hiding the file input is bypassable by direct multipart POST. - Route-level if not disable_files only affects later accounting/status/webhook behavior; it does not prevent the stream sink from creating and writing the file. - Default non-public onion services require the sender to know the onion address and private key unless the user opts into public mode. This limits exposure but does not enforce the user-selected "text only" security policy for authorized senders or public contact-form deployments. - A control case with disable_text=True showed submitted text was not written as a message file, demonstrating the harness was exercising the settings boundary.

Affected versions / patched versions: - Affected versions: unknown; confirmed in version 2.6.3 at commit 8cc75e1d7e88bd31f7276733449d412bf71c8999. Earlier versions were not tested during this audit. - Patched versions: 2.6.4

Severity:

Rationale: AV:N because the Receive endpoint is reached over the OnionShare HTTP service; AC:L because a crafted multipart POST is straightforward once the service is reachable; PR:L because the sender generally needs the OnionShare URL/private key unless the receiver intentionally runs public mode; UI:N because no further receiver interaction is required after service startup; S:U because the same local application writes the file; C:N because this PoC does not read data; I:L because the attacker writes unwanted files in a mode configured to reject files; A:L because the bypass can consume disk/storage despite the files-disabled policy, bounded by available disk and operator controls.

PoC

The following safe local proof uses only temporary directories and Flask's local test client. In this audit environment, several runtime dependencies were absent (waitress, flask_compress, flask_socketio, unidecode, stem, qrcode), so the harness stubbed those imports while executing the real receive_mode request parsing and file writing code. No external network traffic was sent and no real files outside temporary directories were modified.

Maintainer reproduction from a clean checkout with normal dependencies can omit the import stubs and run the same test-client setup, or can start a local Receive service with --disable-files and submit a multipart request to /upload-ajax.

Positive setup and trigger:

import os, tempfile, shutil
from io import BytesIO
from onionshare_cli.common import Common
from onionshare_cli.settings import Settings
from onionshare_cli.mode_settings import ModeSettings
from onionshare_cli.web import Web

base = tempfile.mkdtemp(prefix='os-disable-files-poc-')
data_dir = os.path.join(base, 'receive-data')
os.mkdir(data_dir)

common = Common()
common.settings = Settings(common)
mode_settings = ModeSettings(common)
web = Web(common, False, mode_settings, 'receive')
web.app.testing = True
web.proxies = None
web.settings.set('receive', 'data_dir', data_dir)
web.settings.set('receive', 'disable_files', True)

with web.app.test_client() as c:
    res = c.post(
        '/upload-ajax',
        buffered=True,
        content_type='multipart/form-data',
        data={'file[]': (BytesIO(b'DISABLE_FILES_BYPASS_MARKER'), 'audit.txt')},
    )
    print(res.status_code)
    print(res.get_data(as_text=True))
    for root, dirs, files in os.walk(data_dir):
        for name in files:
            path = os.path.join(root, name)
            print(os.path.relpath(path, data_dir), open(path, 'rb').read().decode())

shutil.rmtree(base)

Observed output from this environment after re-running the proof after drafting:

May 29, 06:13PM: Upload of total size 274.0 B is starting
=> 27.0 B audit.txt          positive_status: 200
positive_response: {"info_flashes": ["Nothing submitted or message was too long (> 524288 characters)"]}
positive_written: [('2026-05-29/181347904165/audit.txt', 'DISABLE_FILES_BYPASS_MARKER')]

The response says nothing/fileless was submitted, but the audit.txt file was created under the Receive data directory.

Negative/control case:

web2.settings.set('receive', 'disable_text', True)
# POST only a text field to /upload-ajax

Observed control output:

control_status: 200
control_response: {"info_flashes": ["Nothing submitted"]}
control_written_files: []
cleanup_done: true

Cleanup: - The PoC deletes all temporary directories with shutil.rmtree(...); the audit run printed cleanup_done: true.

Impact

A Receive service operator can configure OnionShare as a text-only submission endpoint (for example, an anonymous contact form) and still receive attacker-controlled files on disk. This bypasses the explicit user-selected restriction and can lead to unwanted file placement and disk consumption in a deployment where file uploads were intentionally disabled.

The response and GUI/history accounting can be misleading because the route skips file processing while the lower-level request stream has already written the file. This may delay detection by the operator.

The confirmed issue does not provide arbitrary path traversal because filenames are sanitized and writes occur under the configured Receive data directory.

Suggested remediation

Enforce disable_files before any multipart file stream is written, not only in the route handler or template:

  • In ReceiveModeRequest._get_file_stream(), if self.web.settings.get("receive", "disable_files") is true, reject the file part before creating ReceiveModeFile, or route it to a discard stream and mark the request as rejected.
  • Ensure /upload and /upload-ajax return an explicit error when files are submitted while files are disabled.
  • Avoid creating a receive subdirectory for a file-only request that is rejected by policy.
  • Add regression tests for both /upload and /upload-ajax proving no file appears under receive.data_dir when receive.disable_files is true.
  • Add a control regression test proving disable_text still prevents message-file creation.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "onionshare-cli"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.6.4"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-54707"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-31T16:27:59Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\nOnionShare CLI/Desktop 2.6.3 does not enforce the Receive mode `disable_files` setting at the file upload sink. When a Receive service is configured as a text-message-only endpoint (`--disable-files` / \"Disable uploading files\"), a remote sender who can reach the OnionShare service can still send a crafted multipart request containing `file[]`; OnionShare writes the uploaded bytes to disk before the route handler skips file accounting.\n\nThis affects the shipped `onionshare-cli` Python package and the desktop application because both use the same `onionshare_cli.web.receive_mode` request-streaming implementation.\n\n### Details\nTested repository: `https://github.com/onionshare/onionshare` at commit `8cc75e1d7e88bd31f7276733449d412bf71c8999`.\n\nAffected product evidence:\n- `cli/pyproject.toml` declares `onionshare_cli` version `2.6.3`.\n- `desktop/pyproject.toml` declares `onionshare` version `2.6.3` and depends on `onionshare_cli` from `../cli`.\n- `cli/setup.py` publishes `onionshare-cli` and includes `onionshare_cli.web` plus templates/static resources.\n- `desktop/setup.py` publishes `onionshare` and exposes both `onionshare` and `onionshare-cli` console scripts.\n\nReachable default/common paths:\n- CLI Receive mode is exposed through `--receive` (`cli/onionshare_cli/__init__.py:55-57`).\n- The `--disable-files` option is documented and stored in mode settings (`cli/onionshare_cli/__init__.py:156-160`, `cli/onionshare_cli/__init__.py:254-261`).\n- Desktop Receive mode exposes the same setting via the \"Disable uploading files\" checkbox and stores it as `receive.disable_files` (`desktop/onionshare/tab/mode/receive_mode/__init__.py:89-99`, `desktop/onionshare/tab/mode/receive_mode/__init__.py:246-254`).\n- User documentation says \"Disable uploading files\" should \"only allow submitting text messages, like for an anonymous contact form\" (`docs/source/features.rst:64`).\n- Advanced documentation lists `--disable-files` and `disable_files` as the option to disable receiving files (`docs/source/advanced.rst:162-163`, `docs/source/advanced.rst:455`).\n\nRoot cause:\n- The Receive template hides the file input when `disable_files` is set (`cli/onionshare_cli/resources/templates/receive.html:51-56`), but this is only UI-side.\n- The `/upload` route skips `request.files.getlist(\"file[]\")` and file accounting when `disable_files` is enabled (`cli/onionshare_cli/web/receive_mode.py:96-135`). However, by this point Werkzeug has already parsed the multipart body and invoked the custom stream factory.\n- `ReceiveModeRequest.__init__()` treats every `POST /upload` or `POST /upload-ajax` as an upload request and creates a receive directory regardless of `disable_files` (`cli/onionshare_cli/web/receive_mode.py:369-391`).\n- `ReceiveModeRequest._get_file_stream()` creates a writable `ReceiveModeFile` for each uploaded part without checking `self.web.settings.get(\"receive\", \"disable_files\")` (`cli/onionshare_cli/web/receive_mode.py:517-540`).\n- `ReceiveModeFile` opens `\u003creceive_mode_dir\u003e/\u003csecure_filename\u003e.part`, writes attacker-controlled bytes, then renames the `.part` file to the final filename (`cli/onionshare_cli/web/receive_mode.py:272-285`, `cli/onionshare_cli/web/receive_mode.py:320-346`).\n\nFalse-positive screening performed:\n- `secure_filename()` is used at `cli/onionshare_cli/web/receive_mode.py:111-113` and `cli/onionshare_cli/web/receive_mode.py:527-528`, so the confirmed issue is not path traversal; the file is written under the configured receive data directory.\n- The UI hiding the file input is bypassable by direct multipart POST.\n- Route-level `if not disable_files` only affects later accounting/status/webhook behavior; it does not prevent the stream sink from creating and writing the file.\n- Default non-public onion services require the sender to know the onion address and private key unless the user opts into public mode. This limits exposure but does not enforce the user-selected \"text only\" security policy for authorized senders or public contact-form deployments.\n- A control case with `disable_text=True` showed submitted text was not written as a message file, demonstrating the harness was exercising the settings boundary.\n\nAffected versions / patched versions:\n- Affected versions: unknown; confirmed in version `2.6.3` at commit `8cc75e1d7e88bd31f7276733449d412bf71c8999`. Earlier versions were not tested during this audit.\n- Patched versions: 2.6.4\n\nSeverity:\n\n Rationale: `AV:N` because the Receive endpoint is reached over the OnionShare HTTP service; `AC:L` because a crafted multipart POST is straightforward once the service is reachable; `PR:L` because the sender generally needs the OnionShare URL/private key unless the receiver intentionally runs public mode; `UI:N` because no further receiver interaction is required after service startup; `S:U` because the same local application writes the file; `C:N` because this PoC does not read data; `I:L` because the attacker writes unwanted files in a mode configured to reject files; `A:L` because the bypass can consume disk/storage despite the files-disabled policy, bounded by available disk and operator controls.\n\n### PoC\nThe following safe local proof uses only temporary directories and Flask\u0027s local test client. In this audit environment, several runtime dependencies were absent (`waitress`, `flask_compress`, `flask_socketio`, `unidecode`, `stem`, `qrcode`), so the harness stubbed those imports while executing the real `receive_mode` request parsing and file writing code. No external network traffic was sent and no real files outside temporary directories were modified.\n\nMaintainer reproduction from a clean checkout with normal dependencies can omit the import stubs and run the same test-client setup, or can start a local Receive service with `--disable-files` and submit a multipart request to `/upload-ajax`.\n\nPositive setup and trigger:\n```python\nimport os, tempfile, shutil\nfrom io import BytesIO\nfrom onionshare_cli.common import Common\nfrom onionshare_cli.settings import Settings\nfrom onionshare_cli.mode_settings import ModeSettings\nfrom onionshare_cli.web import Web\n\nbase = tempfile.mkdtemp(prefix=\u0027os-disable-files-poc-\u0027)\ndata_dir = os.path.join(base, \u0027receive-data\u0027)\nos.mkdir(data_dir)\n\ncommon = Common()\ncommon.settings = Settings(common)\nmode_settings = ModeSettings(common)\nweb = Web(common, False, mode_settings, \u0027receive\u0027)\nweb.app.testing = True\nweb.proxies = None\nweb.settings.set(\u0027receive\u0027, \u0027data_dir\u0027, data_dir)\nweb.settings.set(\u0027receive\u0027, \u0027disable_files\u0027, True)\n\nwith web.app.test_client() as c:\n    res = c.post(\n        \u0027/upload-ajax\u0027,\n        buffered=True,\n        content_type=\u0027multipart/form-data\u0027,\n        data={\u0027file[]\u0027: (BytesIO(b\u0027DISABLE_FILES_BYPASS_MARKER\u0027), \u0027audit.txt\u0027)},\n    )\n    print(res.status_code)\n    print(res.get_data(as_text=True))\n    for root, dirs, files in os.walk(data_dir):\n        for name in files:\n            path = os.path.join(root, name)\n            print(os.path.relpath(path, data_dir), open(path, \u0027rb\u0027).read().decode())\n\nshutil.rmtree(base)\n```\n\nObserved output from this environment after re-running the proof after drafting:\n```text\nMay 29, 06:13PM: Upload of total size 274.0 B is starting\n=\u003e 27.0 B audit.txt          positive_status: 200\npositive_response: {\"info_flashes\": [\"Nothing submitted or message was too long (\u003e 524288 characters)\"]}\npositive_written: [(\u00272026-05-29/181347904165/audit.txt\u0027, \u0027DISABLE_FILES_BYPASS_MARKER\u0027)]\n```\n\nThe response says nothing/fileless was submitted, but the `audit.txt` file was created under the Receive data directory.\n\nNegative/control case:\n```python\nweb2.settings.set(\u0027receive\u0027, \u0027disable_text\u0027, True)\n# POST only a text field to /upload-ajax\n```\n\nObserved control output:\n```text\ncontrol_status: 200\ncontrol_response: {\"info_flashes\": [\"Nothing submitted\"]}\ncontrol_written_files: []\ncleanup_done: true\n```\n\nCleanup:\n- The PoC deletes all temporary directories with `shutil.rmtree(...)`; the audit run printed `cleanup_done: true`.\n\n### Impact\nA Receive service operator can configure OnionShare as a text-only submission endpoint (for example, an anonymous contact form) and still receive attacker-controlled files on disk. This bypasses the explicit user-selected restriction and can lead to unwanted file placement and disk consumption in a deployment where file uploads were intentionally disabled.\n\nThe response and GUI/history accounting can be misleading because the route skips file processing while the lower-level request stream has already written the file. This may delay detection by the operator.\n\nThe confirmed issue does not provide arbitrary path traversal because filenames are sanitized and writes occur under the configured Receive data directory.\n\n### Suggested remediation\nEnforce `disable_files` before any multipart file stream is written, not only in the route handler or template:\n\n- In `ReceiveModeRequest._get_file_stream()`, if `self.web.settings.get(\"receive\", \"disable_files\")` is true, reject the file part before creating `ReceiveModeFile`, or route it to a discard stream and mark the request as rejected.\n- Ensure `/upload` and `/upload-ajax` return an explicit error when files are submitted while files are disabled.\n- Avoid creating a receive subdirectory for a file-only request that is rejected by policy.\n- Add regression tests for both `/upload` and `/upload-ajax` proving no file appears under `receive.data_dir` when `receive.disable_files` is true.\n- Add a control regression test proving `disable_text` still prevents message-file creation.",
  "id": "GHSA-v833-3823-cmhp",
  "modified": "2026-07-31T16:27:59Z",
  "published": "2026-07-31T16:27:59Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/onionshare/onionshare/security/advisories/GHSA-v833-3823-cmhp"
    },
    {
      "type": "WEB",
      "url": "https://github.com/onionshare/onionshare/commit/a090e97193efc91fbeac9dace7793ea568b83cf5"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/onionshare/onionshare"
    },
    {
      "type": "WEB",
      "url": "https://github.com/onionshare/onionshare/releases/tag/v2.6.4"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L",
      "type": "CVSS_V3"
    }
  ],
  "summary": "OnionShare Receive mode writes uploaded files even when file uploads are disabled"
}

GHSA-V845-M469-P8W3

Vulnerability from github – Published: 2024-06-27 21:32 – Updated: 2025-10-15 15:30
VLAI
Details

In lunary-ai/lunary version 1.2.4, an improper access control vulnerability allows members with team management permissions to manipulate project identifiers in requests, enabling them to invite users to projects in other organizations, change members to projects in other organizations with escalated privileges, and change members from other organizations to their own or other projects, also with escalated privileges. This vulnerability is due to the backend's failure to validate project identifiers against the current user's organization ID and projects belonging to it, as well as a misconfiguration in attribute naming (org_id should be orgId) that prevents proper user organization validation. As a result, attackers can cause inconsistencies on the platform for affected users and organizations, including unauthorized privilege escalation. The issue is present in the backend API endpoints for user invitation and modification, specifically in the handling of project IDs in requests.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-5714"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-284",
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-06-27T19:15:15Z",
    "severity": "HIGH"
  },
  "details": "In lunary-ai/lunary version 1.2.4, an improper access control vulnerability allows members with team management permissions to manipulate project identifiers in requests, enabling them to invite users to projects in other organizations, change members to projects in other organizations with escalated privileges, and change members from other organizations to their own or other projects, also with escalated privileges. This vulnerability is due to the backend\u0027s failure to validate project identifiers against the current user\u0027s organization ID and projects belonging to it, as well as a misconfiguration in attribute naming (`org_id` should be `orgId`) that prevents proper user organization validation. As a result, attackers can cause inconsistencies on the platform for affected users and organizations, including unauthorized privilege escalation. The issue is present in the backend API endpoints for user invitation and modification, specifically in the handling of project IDs in requests.",
  "id": "GHSA-v845-m469-p8w3",
  "modified": "2025-10-15T15:30:19Z",
  "published": "2024-06-27T21:32:08Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-5714"
    },
    {
      "type": "WEB",
      "url": "https://github.com/lunary-ai/lunary/commit/43206bacac3b43ad9f2db6dafd165e61a21e6b97"
    },
    {
      "type": "WEB",
      "url": "https://huntr.com/bounties/8cff4afa-131b-4a7e-9f0d-8a3c69f3d024"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V847-HXXW-3PXG

Vulnerability from github – Published: 2026-06-18 13:53 – Updated: 2026-07-20 21:23
VLAI
Summary
PraisonAI recipe.run_stream skips dangerous-tool policy enforcement
Details

PraisonAI recipe.run_stream() skips dangerous-tool policy enforcement

Summary

PraisonAI recipe execution blocks default-denied dangerous tools unless the caller explicitly passes allow_dangerous_tools=True. The normal recipe.run() path enforces this with _check_tool_policy(). The streaming path, recipe.run_stream(), loads the same recipe, checks dependencies, and then calls _execute_recipe() without running the dangerous-tool policy check.

As a result, a recipe that honestly declares execute_command in TEMPLATE.yaml requires.tools is denied by recipe.run(), but reaches the execution engine through recipe.run_stream() with allow_dangerous_tools=False.

The local PoV uses a harmless printf canary, explicitly unsets PRAISONAI_AUTO_APPROVE, and avoids network access.

Affected Product

  • Repository: MervinPraison/PraisonAI
  • Package: praisonai
  • Components:
  • src/praisonai/praisonai/recipe/core.py
  • src/praisonai/praisonai/recipe/serve.py
  • src/praisonai/praisonai/cli/features/recipe.py
  • src/praisonai-agents/praisonaiagents/workflows/yaml_parser.py
  • src/praisonai-agents/praisonaiagents/workflows/workflows.py

Validated affected:

  • current main 2f9677abb2ea68eab864ee8b6a828fd0141612e1 (v4.6.57-4-g2f9677ab)
  • v4.6.57
  • v4.6.56
  • v4.6.10
  • v4.6.9
  • v4.5.128
  • v4.5.120
  • v4.5.96
  • v4.5.87

Suggested affected range: >= 4.5.87, <= 4.6.57.

PyPI lists PraisonAI 4.6.57 as the latest release on 2026-06-13.

Earlier tested tags through v4.5.85 failed in this source checkout before the tested workflow path due an unrelated praisonaiagents.output.models import error. They are not claimed fixed or unaffected.

Root Cause

recipe.run() enforces the dangerous-tool gate:

if not options.get("allow_dangerous_tools", False):
    policy_error = _check_tool_policy(recipe_config)
    if policy_error:
        return RecipeResult(..., status=RecipeStatus.POLICY_DENIED, ...)

recipe.run_stream() has a sibling execution path. It loads the recipe and checks dependencies, but then goes directly to execution:

recipe_config = _load_recipe(name, offline=options.get("offline", False))
...
output = _execute_recipe(recipe_config, merged_config, session_id, options)

There is no equivalent _check_tool_policy() call in run_stream() before execution or before the dry-run shortcut.

The CLI exposes this path via praisonai recipe run <recipe> --stream, and the recipe HTTP server exposes it as POST /v1/recipes/stream.

Why This Is Not Intended Behavior

The normal recipe path clearly treats declared dangerous tools as denied by default. A control recipe with TEMPLATE.yaml requires.tools: [execute_command] returns:

Tool 'execute_command' is denied by default. Use allow_dangerous_tools=True to override.

That operator-facing override should not depend on whether the caller requests streaming output. PraisonAI's own docs describe approval as requiring a human or configured channel before risky tools run, describe security environment variables as opt-in access for dangerous operations with secure defaults, and describe policy controls as blocking dangerous operations.

This is distinct from the prior report PRAI-CAND-011:

  • PRAI-CAND-011 covers workflow tool declarations that are omitted from TEMPLATE.yaml requires.tools.
  • This report covers a sibling entrypoint that skips the policy check even when TEMPLATE.yaml correctly declares the dangerous tool.

It is also distinct from the published Recipe-server authentication fail-open advisory. That advisory covers missing authentication secrets. This report assumes the attacker has whatever access is already needed to invoke recipe streaming and focuses on the missing dangerous-tool policy guard.

Local PoV

Run:

python3 poc/pov_prai_cand_012_stream_policy_bypass.py

Expected output includes:

{
  "ok": true,
  "policy_error": "Tool 'execute_command' is denied by default. Use allow_dangerous_tools=True to override.",
  "control_recipe_status": "policy_denied",
  "execution_reached": [
    {
      "recipe": "declared-dangerous-stream",
      "declared_required_tools": ["execute_command"],
      "allow_dangerous_tools": false
    }
  ],
  "workflow_approve_tools": ["execute_command"],
  "runner_tool_names": ["execute_command"],
  "command_stdout": "PRAI-CAND-012-CANARY",
  "operator_env_auto_approve": null
}

The PoV creates a temporary recipe that declares execute_command in TEMPLATE.yaml requires.tools.

Control:

  • recipe.run(..., options={"force": True}) returns policy_denied.

Bypass:

  • recipe.run_stream(..., options={"force": True}) emits the executing event and reaches _execute_recipe() while allow_dangerous_tools remains false.
  • The same recipe workflow resolves execute_command and preserves approve: [execute_command].
  • With the workflow approval context installed, the resolved tool runs the harmless local command printf PRAI-CAND-012-CANARY.

The PoV monkey-patches _execute_recipe() only to prove that run_stream() crosses the policy boundary without invoking an LLM. The command canary is executed directly through the same resolved workflow tool and approval context to keep the proof deterministic and local-only.

Impact

If an operator runs an untrusted recipe through streaming mode, or exposes the recipe streaming API to users who can choose recipe names or URIs, the recipe can reach execution with default-denied tools even though the caller did not set allow_dangerous_tools=True.

If the workflow reaches the approved execute_command tool call, commands run with the privileges of the PraisonAI process. The exact trigger depends on the workflow and model/tool-call path, but the dangerous-tool policy boundary is already bypassed before execution.

The HTTP recipe sidecar is documented as a localhost REST API with SSE streaming and optional API-key/JWT authentication. This report does not claim default unauthenticated network RCE. In authenticated or exposed sidecar deployments where lower-trust users can invoke /v1/recipes/stream, the same policy gap can become a remote recipe-execution issue.

Suggested Fix

Centralize recipe preflight enforcement so every execution mode uses the same guard:

  1. Run _check_tool_policy(recipe_config) in run_stream() unless options["allow_dangerous_tools"] is true.
  2. Perform that check before both dry-run and real execution, matching recipe.run().
  3. Prefer a shared helper for dependency checks, dangerous-tool policy checks, and dry-run handling so future entrypoints cannot drift.
  4. Add regression tests:
  5. declared dangerous tool is denied by recipe.run();
  6. the same declared dangerous tool is denied by recipe.run_stream();
  7. allow_dangerous_tools=True preserves the intended opt-in behavior;
  8. /v1/recipes/stream maps a policy denial to a non-success SSE event or equivalent HTTP failure.
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 4.6.58"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "praisonai"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.5.87"
            },
            {
              "fixed": "4.6.59"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-56838"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-693",
      "CWE-78",
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T13:53:05Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "# PraisonAI `recipe.run_stream()` skips dangerous-tool policy enforcement\n\n## Summary\n\nPraisonAI recipe execution blocks default-denied dangerous tools unless the\ncaller explicitly passes `allow_dangerous_tools=True`. The normal `recipe.run()`\npath enforces this with `_check_tool_policy()`. The streaming path,\n`recipe.run_stream()`, loads the same recipe, checks dependencies, and then\ncalls `_execute_recipe()` without running the dangerous-tool policy check.\n\nAs a result, a recipe that honestly declares `execute_command` in\n`TEMPLATE.yaml requires.tools` is denied by `recipe.run()`, but reaches the\nexecution engine through `recipe.run_stream()` with\n`allow_dangerous_tools=False`.\n\nThe local PoV uses a harmless `printf` canary, explicitly unsets\n`PRAISONAI_AUTO_APPROVE`, and avoids network access.\n\n## Affected Product\n\n- Repository: `MervinPraison/PraisonAI`\n- Package: `praisonai`\n- Components:\n  - `src/praisonai/praisonai/recipe/core.py`\n  - `src/praisonai/praisonai/recipe/serve.py`\n  - `src/praisonai/praisonai/cli/features/recipe.py`\n  - `src/praisonai-agents/praisonaiagents/workflows/yaml_parser.py`\n  - `src/praisonai-agents/praisonaiagents/workflows/workflows.py`\n\nValidated affected:\n\n- current main `2f9677abb2ea68eab864ee8b6a828fd0141612e1`\n  (`v4.6.57-4-g2f9677ab`)\n- `v4.6.57`\n- `v4.6.56`\n- `v4.6.10`\n- `v4.6.9`\n- `v4.5.128`\n- `v4.5.120`\n- `v4.5.96`\n- `v4.5.87`\n\nSuggested affected range: `\u003e= 4.5.87, \u003c= 4.6.57`.\n\nPyPI lists `PraisonAI 4.6.57` as the latest release on 2026-06-13.\n\nEarlier tested tags through `v4.5.85` failed in this source checkout before the\ntested workflow path due an unrelated `praisonaiagents.output.models` import\nerror. They are not claimed fixed or unaffected.\n\n## Root Cause\n\n`recipe.run()` enforces the dangerous-tool gate:\n\n```python\nif not options.get(\"allow_dangerous_tools\", False):\n    policy_error = _check_tool_policy(recipe_config)\n    if policy_error:\n        return RecipeResult(..., status=RecipeStatus.POLICY_DENIED, ...)\n```\n\n`recipe.run_stream()` has a sibling execution path. It loads the recipe and\nchecks dependencies, but then goes directly to execution:\n\n```python\nrecipe_config = _load_recipe(name, offline=options.get(\"offline\", False))\n...\noutput = _execute_recipe(recipe_config, merged_config, session_id, options)\n```\n\nThere is no equivalent `_check_tool_policy()` call in `run_stream()` before\nexecution or before the dry-run shortcut.\n\nThe CLI exposes this path via `praisonai recipe run \u003crecipe\u003e --stream`, and the\nrecipe HTTP server exposes it as `POST /v1/recipes/stream`.\n\n## Why This Is Not Intended Behavior\n\nThe normal recipe path clearly treats declared dangerous tools as denied by\ndefault. A control recipe with `TEMPLATE.yaml requires.tools:\n[execute_command]` returns:\n\n```text\nTool \u0027execute_command\u0027 is denied by default. Use allow_dangerous_tools=True to override.\n```\n\nThat operator-facing override should not depend on whether the caller requests\nstreaming output. PraisonAI\u0027s own docs describe approval as requiring a human\nor configured channel before risky tools run, describe security environment\nvariables as opt-in access for dangerous operations with secure defaults, and\ndescribe policy controls as blocking dangerous operations.\n\nThis is distinct from the prior report `PRAI-CAND-011`:\n\n- `PRAI-CAND-011` covers workflow tool declarations that are omitted from\n  `TEMPLATE.yaml requires.tools`.\n- This report covers a sibling entrypoint that skips the policy check even when\n  `TEMPLATE.yaml` correctly declares the dangerous tool.\n\nIt is also distinct from the published Recipe-server authentication fail-open\nadvisory. That advisory covers missing authentication secrets. This report\nassumes the attacker has whatever access is already needed to invoke recipe\nstreaming and focuses on the missing dangerous-tool policy guard.\n\n## Local PoV\n\nRun:\n\n```bash\npython3 poc/pov_prai_cand_012_stream_policy_bypass.py\n```\n\nExpected output includes:\n\n```json\n{\n  \"ok\": true,\n  \"policy_error\": \"Tool \u0027execute_command\u0027 is denied by default. Use allow_dangerous_tools=True to override.\",\n  \"control_recipe_status\": \"policy_denied\",\n  \"execution_reached\": [\n    {\n      \"recipe\": \"declared-dangerous-stream\",\n      \"declared_required_tools\": [\"execute_command\"],\n      \"allow_dangerous_tools\": false\n    }\n  ],\n  \"workflow_approve_tools\": [\"execute_command\"],\n  \"runner_tool_names\": [\"execute_command\"],\n  \"command_stdout\": \"PRAI-CAND-012-CANARY\",\n  \"operator_env_auto_approve\": null\n}\n```\n\nThe PoV creates a temporary recipe that declares `execute_command` in\n`TEMPLATE.yaml requires.tools`.\n\nControl:\n\n- `recipe.run(..., options={\"force\": True})` returns `policy_denied`.\n\nBypass:\n\n- `recipe.run_stream(..., options={\"force\": True})` emits the `executing`\n  event and reaches `_execute_recipe()` while `allow_dangerous_tools` remains\n  false.\n- The same recipe workflow resolves `execute_command` and preserves\n  `approve: [execute_command]`.\n- With the workflow approval context installed, the resolved tool runs the\n  harmless local command `printf PRAI-CAND-012-CANARY`.\n\nThe PoV monkey-patches `_execute_recipe()` only to prove that\n`run_stream()` crosses the policy boundary without invoking an LLM. The command\ncanary is executed directly through the same resolved workflow tool and\napproval context to keep the proof deterministic and local-only.\n\n## Impact\n\nIf an operator runs an untrusted recipe through streaming mode, or exposes the\nrecipe streaming API to users who can choose recipe names or URIs, the recipe\ncan reach execution with default-denied tools even though the caller did not\nset `allow_dangerous_tools=True`.\n\nIf the workflow reaches the approved `execute_command` tool call, commands run\nwith the privileges of the PraisonAI process. The exact trigger depends on the\nworkflow and model/tool-call path, but the dangerous-tool policy boundary is\nalready bypassed before execution.\n\nThe HTTP recipe sidecar is documented as a localhost REST API with SSE\nstreaming and optional API-key/JWT authentication. This report does not claim\ndefault unauthenticated network RCE. In authenticated or exposed sidecar\ndeployments where lower-trust users can invoke `/v1/recipes/stream`, the same\npolicy gap can become a remote recipe-execution issue.\n\n## Suggested Fix\n\nCentralize recipe preflight enforcement so every execution mode uses the same\nguard:\n\n1. Run `_check_tool_policy(recipe_config)` in `run_stream()` unless\n   `options[\"allow_dangerous_tools\"]` is true.\n2. Perform that check before both dry-run and real execution, matching\n   `recipe.run()`.\n3. Prefer a shared helper for dependency checks, dangerous-tool policy checks,\n   and dry-run handling so future entrypoints cannot drift.\n4. Add regression tests:\n   - declared dangerous tool is denied by `recipe.run()`;\n   - the same declared dangerous tool is denied by `recipe.run_stream()`;\n   - `allow_dangerous_tools=True` preserves the intended opt-in behavior;\n   - `/v1/recipes/stream` maps a policy denial to a non-success SSE event or\n     equivalent HTTP failure.",
  "id": "GHSA-v847-hxxw-3pxg",
  "modified": "2026-07-20T21:23:42Z",
  "published": "2026-06-18T13:53:05Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-v847-hxxw-3pxg"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/MervinPraison/PraisonAI"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "PraisonAI recipe.run_stream skips dangerous-tool policy enforcement"
}

GHSA-V84C-53C6-XMMP

Vulnerability from github – Published: 2024-11-26 21:32 – Updated: 2024-11-26 21:32
VLAI
Details

An issue was discovered in GitLab CE/EE affecting all versions from 16.9.8 before 17.4.5, 17.5 before 17.5.3, and 17.6 before 17.6.1. Certain API endpoints could potentially allow unauthorized access to sensitive data due to overly broad application of token scopes.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-11669"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-11-26T19:15:22Z",
    "severity": "MODERATE"
  },
  "details": "An issue was discovered in GitLab CE/EE affecting all versions from 16.9.8 before 17.4.5, 17.5 before 17.5.3, and 17.6 before 17.6.1. Certain API endpoints could potentially allow unauthorized access to sensitive data due to overly broad application of token scopes.",
  "id": "GHSA-v84c-53c6-xmmp",
  "modified": "2024-11-26T21:32:24Z",
  "published": "2024-11-26T21:32:24Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-11669"
    },
    {
      "type": "WEB",
      "url": "https://gitlab.com/gitlab-org/gitlab/-/issues/501528"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V856-JMJ2-XMV3

Vulnerability from github – Published: 2023-09-08 21:30 – Updated: 2024-04-04 07:34
VLAI
Details

IBM Aspera Faspex 5.0.5 could allow a malicious actor to bypass IP whitelist restrictions using a specially crafted HTTP request. IBM X-Force ID: 254268.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2023-30995"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2023-09-08T21:15:45Z",
    "severity": "HIGH"
  },
  "details": "IBM Aspera Faspex 5.0.5 could allow a malicious actor to bypass IP whitelist restrictions using a specially crafted HTTP request.  IBM X-Force ID:  254268.",
  "id": "GHSA-v856-jmj2-xmv3",
  "modified": "2024-04-04T07:34:20Z",
  "published": "2023-09-08T21:30:35Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-30995"
    },
    {
      "type": "WEB",
      "url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/254268"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/7029681"
    },
    {
      "type": "WEB",
      "url": "https://www.ibm.com/support/pages/node/7048851"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V85R-M9WC-PPRX

Vulnerability from github – Published: 2024-10-15 21:30 – Updated: 2024-10-15 21:30
VLAI
Details

Vulnerability in the Oracle Site Hub product of Oracle E-Business Suite (component: Site Hierarchy Flows). Supported versions that are affected are 12.2.3-12.2.13. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise Oracle Site Hub. Successful attacks of this vulnerability can result in unauthorized creation, deletion or modification access to critical data or all Oracle Site Hub accessible data as well as unauthorized access to critical data or complete access to all Oracle Site Hub accessible data. CVSS 3.1 Base Score 8.1 (Confidentiality and Integrity impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-21265"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-10-15T20:15:17Z",
    "severity": "HIGH"
  },
  "details": "Vulnerability in the Oracle Site Hub product of Oracle E-Business Suite (component: Site Hierarchy Flows).  Supported versions that are affected are 12.2.3-12.2.13. Easily exploitable vulnerability allows low privileged attacker with network access via HTTP to compromise Oracle Site Hub.  Successful attacks of this vulnerability can result in  unauthorized creation, deletion or modification access to critical data or all Oracle Site Hub accessible data as well as  unauthorized access to critical data or complete access to all Oracle Site Hub accessible data. CVSS 3.1 Base Score 8.1 (Confidentiality and Integrity impacts).  CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N).",
  "id": "GHSA-v85r-m9wc-pprx",
  "modified": "2024-10-15T21:30:38Z",
  "published": "2024-10-15T21:30:38Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-21265"
    },
    {
      "type": "WEB",
      "url": "https://www.oracle.com/security-alerts/cpuoct2024.html"
    }
  ],
  "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:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V86M-GG8V-4873

Vulnerability from github – Published: 2026-04-10 03:31 – Updated: 2026-04-10 03:31
VLAI
Details

The WP-Optimize plugin for WordPress is vulnerable to unauthorized access of functionality due to missing capability checks in the receive_heartbeat() function in includes/class-wp-optimize-heartbeat.php in all versions up to, and including, 4.5.0. This is due to the Heartbeat handler directly invoking Updraft_Smush_Manager_Commands methods without verifying user capabilities, nonce tokens, or the allowed commands whitelist that the normal AJAX handler (updraft_smush_ajax) enforces. This makes it possible for authenticated attackers, with Subscriber-level access and above, to invoke admin-only Smush operations including reading log files (get_smush_logs), deleting all backup images (clean_all_backup_images), triggering bulk image processing (process_bulk_smush), and modifying Smush options (update_smush_options).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-2712"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-04-10T02:16:02Z",
    "severity": "MODERATE"
  },
  "details": "The WP-Optimize plugin for WordPress is vulnerable to unauthorized access of functionality due to missing capability checks in the `receive_heartbeat()` function in `includes/class-wp-optimize-heartbeat.php` in all versions up to, and including, 4.5.0. This is due to the Heartbeat handler directly invoking `Updraft_Smush_Manager_Commands` methods without verifying user capabilities, nonce tokens, or the allowed commands whitelist that the normal AJAX handler (`updraft_smush_ajax`) enforces. This makes it possible for authenticated attackers, with Subscriber-level access and above, to invoke admin-only Smush operations including reading log files (`get_smush_logs`), deleting all backup images (`clean_all_backup_images`), triggering bulk image processing (`process_bulk_smush`), and modifying Smush options (`update_smush_options`).",
  "id": "GHSA-v86m-gg8v-4873",
  "modified": "2026-04-10T03:31:10Z",
  "published": "2026-04-10T03:31:10Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2712"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/wp-optimize/tags/4.4.1/includes/class-wp-optimize-heartbeat.php#L65"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/wp-optimize/tags/4.4.1/includes/class-wp-optimize-heartbeat.php#L82"
    },
    {
      "type": "WEB",
      "url": "https://plugins.trac.wordpress.org/browser/wp-optimize/trunk/includes/class-wp-optimize-heartbeat.php#L65"
    },
    {
      "type": "WEB",
      "url": "https://research.cleantalk.org/cve-2026-2712"
    },
    {
      "type": "WEB",
      "url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/6a0a376e-ea3a-40ca-9341-f28f92e15e02?source=cve"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V87M-P66Q-XCJG

Vulnerability from github – Published: 2026-09-14 15:32 – Updated: 2026-09-14 15:32
VLAI
Details

Mattermost versions 11.9.x <= 11.9.0, 11.8.x <= 11.8.4, 11.7.x <= 11.7.7 fail to enforce authorization boundaries on the access control policy update endpoint which allows a channel or team administrator to detach a system-assigned ABAC parent policy via a crafted PUT /api/v4/access_control_policies request with an empty imports list.. Mattermost Advisory ID: MMSA-2026-00724

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-82920"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-09-14T14:17:13Z",
    "severity": "MODERATE"
  },
  "details": "Mattermost versions 11.9.x \u003c= 11.9.0, 11.8.x \u003c= 11.8.4, 11.7.x \u003c= 11.7.7 fail to enforce authorization boundaries on the access control policy update endpoint which allows a channel or team administrator to detach a system-assigned ABAC parent policy via a crafted PUT /api/v4/access_control_policies request with an empty imports list.. Mattermost Advisory ID: MMSA-2026-00724",
  "id": "GHSA-v87m-p66q-xcjg",
  "modified": "2026-09-14T15:32:46Z",
  "published": "2026-09-14T15:32:46Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-82920"
    },
    {
      "type": "WEB",
      "url": "https://mattermost.com/security-updates"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-V8CG-4474-49V8

Vulnerability from github – Published: 2026-03-12 14:21 – Updated: 2026-03-30 13:39
VLAI
Summary
OpenClaw: Slack system events bypass sender authorization in member and message subtype handlers
Details

Summary

Slack member_* and message subtype system events (message_changed, message_deleted, thread_broadcast) were not consistently enforcing sender authorization before enqueueing system events.

Affected Packages / Versions

  • Package: openclaw (npm)
  • Latest published version: 2026.2.25
  • Affected range: <= 2026.2.25
  • Planned patched version: 2026.2.26 (pre-set for publish-readiness)

Technical Details

Slack system-event handlers in src/slack/monitor/events/members.ts and src/slack/monitor/events/messages.ts enqueued events after channel checks without shared sender authorization. Deployments relying on Slack DM allowlists (dmPolicy / allowFrom) or per-channel users allowlists could receive unauthorized system-event ingress from non-allowlisted senders.

The fix routes those handlers through authorizeAndResolveSlackSystemEventContext(...) and fails closed when message subtype sender identity cannot be resolved.

Fix Commit(s)

  • 3d30ba18a2aba1e1b302e77ff33145c3b06c01c8

Release Process Note

patched_versions is pre-set to >= 2026.2.26 so once npm 2026.2.26 is published, this advisory can be published without further field edits.

Thanks @tdjackey for reporting.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2026.2.25"
      },
      "package": {
        "ecosystem": "npm",
        "name": "openclaw"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2026.2.26"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-32895"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-863"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-12T14:21:59Z",
    "nvd_published_at": null,
    "severity": "MODERATE"
  },
  "details": "### Summary\nSlack `member_*` and `message` subtype system events (`message_changed`, `message_deleted`, `thread_broadcast`) were not consistently enforcing sender authorization before enqueueing system events.\n\n### Affected Packages / Versions\n- Package: `openclaw` (npm)\n- Latest published version: `2026.2.25`\n- Affected range: `\u003c= 2026.2.25`\n- Planned patched version: `2026.2.26` (pre-set for publish-readiness)\n\n### Technical Details\nSlack system-event handlers in `src/slack/monitor/events/members.ts` and `src/slack/monitor/events/messages.ts` enqueued events after channel checks without shared sender authorization. Deployments relying on Slack DM allowlists (`dmPolicy` / `allowFrom`) or per-channel `users` allowlists could receive unauthorized system-event ingress from non-allowlisted senders.\n\nThe fix routes those handlers through `authorizeAndResolveSlackSystemEventContext(...)` and fails closed when message subtype sender identity cannot be resolved.\n\n### Fix Commit(s)\n- `3d30ba18a2aba1e1b302e77ff33145c3b06c01c8`\n\n### Release Process Note\n`patched_versions` is pre-set to `\u003e= 2026.2.26` so once npm `2026.2.26` is published, this advisory can be published without further field edits.\n\nThanks @tdjackey for reporting.",
  "id": "GHSA-v8cg-4474-49v8",
  "modified": "2026-03-30T13:39:01Z",
  "published": "2026-03-12T14:21:59Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/security/advisories/GHSA-v8cg-4474-49v8"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-32895"
    },
    {
      "type": "WEB",
      "url": "https://github.com/openclaw/openclaw/commit/3d30ba18a2aba1e1b302e77ff33145c3b06c01c8"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/openclaw/openclaw"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/openclaw-sender-authorization-bypass-in-slack-system-event-handlers"
    }
  ],
  "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"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "OpenClaw: Slack system events bypass sender authorization in member and message subtype handlers"
}

GHSA-V8CV-CH4W-445W

Vulnerability from github – Published: 2022-06-14 00:00 – Updated: 2024-09-17 00:31
VLAI
Details

In Festo Controller CECC-X-M1 product family in multiple versions, the http-endpoint "cecc-x-refresh-request" POST request doesn’t check for port syntax. This can result in unauthorized execution of system commands with root privileges due to improper access control command injection.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-30311"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-78",
      "CWE-863"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-06-13T14:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "In Festo Controller CECC-X-M1 product family in multiple versions, the http-endpoint \"cecc-x-refresh-request\" POST request doesn\u00e2\u20ac\u2122t check for port syntax. This can result in unauthorized execution of system commands with root privileges due to improper access control command injection.",
  "id": "GHSA-v8cv-ch4w-445w",
  "modified": "2024-09-17T00:31:00Z",
  "published": "2022-06-14T00:00:35Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-30311"
    },
    {
      "type": "WEB",
      "url": "https://cert.vde.com/en/advisories/VDE-2022-020"
    }
  ],
  "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"
    }
  ]
}

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.