Skip to content

PraisonAI DiscordApproval accepts unrelated channel messages as dangerous-tool approvals

High severity GitHub Reviewed Published Jun 17, 2026 in MervinPraison/PraisonAI • Updated Jun 18, 2026

Package

pip praisonai (pip)

Affected versions

>= 4.5.2, <= 4.6.58

Patched versions

4.6.59

Description

DiscordApproval accepts unrelated channel messages as dangerous-tool approvals

Summary

praisonai.bots.DiscordApproval approves a pending dangerous tool call when it
sees any later non-bot message in the configured Discord channel whose text is
classified as approval, such as yes.

The decision is not bound to:

  • a Discord reply to the approval message;
  • a Discord thread created for that request;
  • a Discord interaction/button callback for that request;
  • an explicit approver user allowlist; or
  • an approval nonce visible only to intended approvers.

As a result, any user who can post in the configured approval channel can
approve a pending high-risk tool call by sending yes after the approval
message appears. The same local PoV also shows that the Slack and Telegram
messaging approval backends have no explicit approver allowlist parameter, but
the primary report-grade issue is the Discord backend's unthreaded channel
cross-talk: the approving message does not need to be a reply or otherwise
request-bound.

Affected Product

  • Repository: MervinPraison/PraisonAI
  • Ecosystem: pip
  • Package: praisonai
  • Component: Python messaging approval backends
  • Primary affected file: src/praisonai/praisonai/bots/_discord_approval.py
  • Related sibling files:
    • src/praisonai/praisonai/bots/_slack_approval.py
    • src/praisonai/praisonai/bots/_telegram_approval.py
  • Latest PyPI version validated: 4.6.58
  • Current origin/main validated:
    1ad58ca02975ff1398efeda694ea2ab78f20cf3e
  • Current origin/main tag validated: v4.6.58

Suggested affected range:

pip:praisonai >= 4.5.2, <= 4.6.58

Representative local sweep:

4.5.0    Discord approval backend not present
4.5.2    vulnerable
4.5.128  vulnerable
4.6.9    vulnerable
4.6.10   vulnerable
4.6.56   vulnerable
4.6.57   vulnerable
4.6.58   vulnerable

Root Cause

DiscordApproval.request_approval() posts an approval message to the configured
channel and records the returned message id.

_poll_for_response() then polls channel history with:

f"/channels/{channel_id}/messages?after={message_id}&limit=10"

For each later non-bot message, it reads content, classifies the text, and
returns ApprovalDecision(approved=True) when the text is approve/yes.
There is no check that the message is a Discord reply to the approval message,
belongs to a request-specific thread, came from an intended approver, or
contains a request-specific approval token.

Important source evidence from origin/main:

  • _discord_approval.py lines 57-73: constructor accepts token,
    channel_id, timeout, and poll_interval; no approver allowlist.
  • _discord_approval.py line 239: polls all messages after the approval
    message in the configured channel.
  • _discord_approval.py lines 252-265: skips bot messages, classifies the
    remaining text, and approves when the keyword is approve.

The Slack and Telegram backends are better request-scoped than Discord:

  • Slack uses conversations.replies for the approval message thread.
  • Telegram checks the callback/reply message id.

However, both still lack an explicit approver identity parameter. They are
included in the PoV and suggested fix because the authorization model should be
consistent across all messaging approval backends.

Local PoV

Run against the latest local checkout:

python3 poc/pov_prai_cand_029_messaging_approval_channel_member_bypass.py \
  --repo ../../artifacts/repos/praisonai-v4.6.58 \
  --json

The PoV is local-only. It mocks Slack, Telegram, and Discord API helpers
in-process and does not contact those services.

For Discord, the mock sequence is:

  1. DiscordApproval posts a critical execute_command approval request to
    D_APPROVAL_CHANNEL.
  2. The mocked channel-history endpoint returns a later ordinary non-bot
    channel message from D_INTRUDER with content yes.
  3. DiscordApproval returns approved=True and approver="D_INTRUDER".

Observed output from evidence/pov-v4.6.58.json:

{
  "approval_from_unconfigured_channel_participant": {
    "discord": true,
    "slack": true,
    "telegram": true
  },
  "backends": [
    {
      "backend": "discord",
      "configured_channel_id": "D_APPROVAL_CHANNEL",
      "decision_approved": true,
      "decision_approver": "D_INTRUDER",
      "decision_reason": "Approved via Discord by intruder",
      "intruder_user": "D_INTRUDER"
    }
  ],
  "no_explicit_approver_allowlist_parameters": true,
  "vulnerable": true
}

The command in the approval request is a harmless local sentinel:
touch /tmp/prai-cand-029. The PoV stops at the approval decision; it does not
execute the tool.

Why This Is Not Intended Behavior

This report does not claim that a deliberately private approval channel with
only trusted approvers is unsafe by itself. The narrower issue is that the
Discord backend treats an unrelated later channel message as the approval
decision for a specific dangerous tool request.

PraisonAI's approval documentation describes approval as a safety control that
pauses before dangerous tools and asks a human or channel to allow or deny the
specific request. A random later yes in the channel is not evidence that an
intended approver reviewed that request.

The existing Slack and Telegram implementations already show request-binding
patterns that Discord lacks:

  • Slack scopes to replies for the approval message timestamp.
  • Telegram checks the callback/reply message_id.

The Discord backend should provide at least the same request binding and should
also support explicit approver identity checks for deployments where channel
membership is broader than approval authority.

Impact

If an application uses DiscordApproval for dangerous tools such as shell
commands, file writes, deletes, deployments, or other privileged operations, a
low-privileged Discord user with write access to the configured approval channel
can approve pending dangerous tool executions.

This can lead to code execution, file modification, deployment changes, or data
access with the privileges of the PraisonAI process, depending on which tools
the agent exposes behind approval.

The attacker does not need the LLM API key, shell access, repository access, or
PraisonAI process access. They only need to be able to post an approval-looking
message in the configured approval channel after the approval prompt appears.

Severity

Suggested severity: High.

Rationale:

  • AV: the attacker interacts through a networked Discord channel.
  • AC: sending yes after an approval prompt is enough.
  • PR: the attacker needs permission to post in the configured approval
    channel, but no approver-specific permission.
  • UI: no separate victim interaction is needed after the prompt exists.
  • S: the vulnerable approval backend and approved tool run in the PraisonAI
    application's security scope.
  • C/I/A: approved dangerous tools can disclose, modify, or destroy data
    depending on the configured agent tools.

Remediation

Recommended fixes:

  1. For Discord, require approvals to be tied to the request, not merely any
    later channel message. Use Discord interactions/buttons with opaque
    server-side request ids, or require a Discord reply whose
    message_reference.message_id matches the approval message.
  2. Add explicit approver identity configuration to all messaging approval
    backends, for example approver_user_ids or allowed_approvers.
  3. Reject approvals from users outside the configured approver set, even if the
    message appears in the configured channel.
  4. Include a per-request nonce or opaque approval id in callbacks and verify it
    server side before returning ApprovalDecision(approved=True).
  5. Add regression tests for Discord where:
    • an unrelated later yes in the channel is ignored;
    • a reply from a non-approver is ignored;
    • a request-bound reply/callback from an allowed approver succeeds.

References

@MervinPraison MervinPraison published to MervinPraison/PraisonAI Jun 17, 2026
Published to the GitHub Advisory Database Jun 18, 2026
Reviewed Jun 18, 2026
Last updated Jun 18, 2026

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

EPSS score

Weaknesses

Insufficient Verification of Data Authenticity

The product does not sufficiently verify the origin or authenticity of data, in a way that causes it to accept invalid data. Learn more on MITRE.

Incorrect Authorization

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. Learn more on MITRE.

CVE ID

No known CVE

GHSA ID

GHSA-8579-rgg5-ph2m

Credits

Loading Checking history
See something to contribute? Suggest improvements for this vulnerability.