Every CVE Search/ Get API key

CVE-2026-60087

PraisonAI before 1.6.78 Tool Approval Cache Bypass

6.9 MediumFix available

PraisonAI before 1.6.78 caches tool approval decisions by tool name only, allowing attackers to reuse initial approvals for subsequent calls with arbitrary arguments. Attackers can exploit this by obtaining approval for a benign operation and then executing dangerous file write operations with unreviewed parameters in the same session.

Attack profile

How easy it is to exploit

Attack vector
Local
Complexity
Low
Privileges needed
None
User interaction
Passive

What an attacker can affect

Confidentiality
None
Integrity
High
Availability
Low

Exploit likelihood

0.34%Up 0.1 points since Jul 16, 2026
90%50%10%1%

What each source reports

CVE List Score used 6.9

PraisonAI before 1.6.78 Tool Approval Cache Bypass

PraisonAI before 1.6.78 caches tool approval decisions by tool name only, allowing attackers to reuse initial approvals for subsequent calls with arbitrary arguments. Attackers can exploit this by obtaining approval for a benign operation and then executing dangerous file write operations with unreviewed parameters in the same session.

Record
CVE-2026-60087
CVSS 4.0
6.9 MediumCVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L
Weakness
CWE-863
Updated
2026-11-02
EUVDEUVD-2026-44637 6.9

PraisonAI before 1.6.78 caches tool approval decisions by tool name only, allowing attackers to reuse initial approvals for subsequent calls with arbitrary arguments. Attackers can exploit this by obtaining approval for a benign operation and then executing dangerous file write operations with unreviewed parameters in the same session.

Record
EUVD-2026-44637
CVSS 4.0
6.9 MediumCVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-29r9-67vg-qj56 6.1

PraisonAI: Human-in-the-loop tool approval is cached by tool name and silently reused for all subsequent calls with arbitrary arguments

Summary

PraisonAI gates dangerous tools (file writes, deletes, shell/code execution) behind an interactive approval prompt. The first approval of a tool is cached for the remainder of the run and silently reused for all later invocations of that tool with arbitrary, unreviewed arguments.

Root cause

ApprovalRegistry.is_already_approved (src/praisonai-agents/praisonaiagents/approval/registry.py, around line 181) returns True whenever the tool name is present in a per-run context set. The cache is keyed on tool name only — arguments are not part of the key.

approve_sync / approve_async (around lines 224-226 / 278-279) short-circuit on that cache before the approval backend is consulted.

clear_approved (around lines 186-187) is the only routine that clears the cache, but it is never invoked in the shipped library (only in tests). The cache persists for the entire agent run and is inherited by child tasks via contextvars.

Critical-tier tools (execute_command, execute_code) are exempt from the cache. But high-risk tools like write_file are not.

Proof of concept

from praisonaiagents.approval.registry import ApprovalRegistry
from praisonaiagents.approval.protocols import ApprovalDecision, ApprovalRequest

class CountingBackend:
    def __init__(self): self.prompts = []
    def request_approval_sync(self, request):
        self.prompts.append((request.tool_name, dict(request.arguments)))
        return ApprovalDecision(approved=True, reason="human approved")

backend = CountingBackend()
reg = ApprovalRegistry()
reg.set_backend(backend)
reg.add_requirement("write_file", "high")

d1 = reg.approve_sync("agent", "write_file", {"path": "/tmp/safe.txt", "content": "hi"})
# Human prompted — approves a benign write

d2 = reg.approve_sync("agent", "write_file", {"path": "/etc/crontab", "content": "* * * * * root evil"})
# NO prompt — auto-approved from cache

assert len(backend.prompts) == 1
assert d2.reason == "Already approved in context"

Negative control: execute_command (critical) re-prompts on every call — 2 prompts for 2 calls.

Impact

A write_file approval for a benign path authorizes every later write_file call in the session with arbitrary arguments. A model steered by malicious input can write to sensitive locations with no further human prompt.

Suggested fix

  • Include arguments in the approval cache key, or re-prompt on argument change.
  • Expire the cache per-call or per-turn.
  • Do not inherit the cache into child tasks.
Record
GHSA-29r9-67vg-qj56
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L
Weakness
CWE-863
Updated
2026-11-02
GitHub AdvisoriesGHSA-r3xw-gcpr-rf26 6.9

Duplicate Advisory: PraisonAI: Human-in-the-loop tool approval is cached by tool name and silently reused for all subsequent calls with arbitrary arguments

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-29r9-67vg-qj56. This link is maintained to preserve external references.

Original Description

PraisonAI before 1.6.78 caches tool approval decisions by tool name only, allowing attackers to reuse initial approvals for subsequent calls with arbitrary arguments. Attackers can exploit this by obtaining approval for a benign operation and then executing dangerous file write operations with unreviewed parameters in the same session.

Record
GHSA-r3xw-gcpr-rf26
CVSS 4.0
6.9 MediumCVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L
Weakness
CWE-863
Updated
2026-11-02
NVD 6.9

PraisonAI before 1.6.78 caches tool approval decisions by tool name only, allowing attackers to reuse initial approvals for subsequent calls with arbitrary arguments. Attackers can exploit this by obtaining approval for a benign operation and then executing dangerous file write operations with unreviewed parameters in the same session.

Record
CVE-2026-60087
CVSS 4.0
6.9 MediumCVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L
Weakness
CWE-863
Updated
2026-11-02
OSVGHSA-29r9-67vg-qj56 6.1

PraisonAI: Human-in-the-loop tool approval is cached by tool name and silently reused for all subsequent calls with arbitrary arguments

Summary

PraisonAI gates dangerous tools (file writes, deletes, shell/code execution) behind an interactive approval prompt. The first approval of a tool is cached for the remainder of the run and silently reused for all later invocations of that tool with arbitrary, unreviewed arguments.

Root cause

ApprovalRegistry.is_already_approved (src/praisonai-agents/praisonaiagents/approval/registry.py, around line 181) returns True whenever the tool name is present in a per-run context set. The cache is keyed on tool name only — arguments are not part of the key.

approve_sync / approve_async (around lines 224-226 / 278-279) short-circuit on that cache before the approval backend is consulted.

clear_approved (around lines 186-187) is the only routine that clears the cache, but it is never invoked in the shipped library (only in tests). The cache persists for the entire agent run and is inherited by child tasks via contextvars.

Critical-tier tools (execute_command, execute_code) are exempt from the cache. But high-risk tools like write_file are not.

Proof of concept

from praisonaiagents.approval.registry import ApprovalRegistry
from praisonaiagents.approval.protocols import ApprovalDecision, ApprovalRequest

class CountingBackend:
    def __init__(self): self.prompts = []
    def request_approval_sync(self, request):
        self.prompts.append((request.tool_name, dict(request.arguments)))
        return ApprovalDecision(approved=True, reason="human approved")

backend = CountingBackend()
reg = ApprovalRegistry()
reg.set_backend(backend)
reg.add_requirement("write_file", "high")

d1 = reg.approve_sync("agent", "write_file", {"path": "/tmp/safe.txt", "content": "hi"})
# Human prompted — approves a benign write

d2 = reg.approve_sync("agent", "write_file", {"path": "/etc/crontab", "content": "* * * * * root evil"})
# NO prompt — auto-approved from cache

assert len(backend.prompts) == 1
assert d2.reason == "Already approved in context"

Negative control: execute_command (critical) re-prompts on every call — 2 prompts for 2 calls.

Impact

A write_file approval for a benign path authorizes every later write_file call in the session with arbitrary arguments. A model steered by malicious input can write to sensitive locations with no further human prompt.

Suggested fix

  • Include arguments in the approval cache key, or re-prompt on argument change.
  • Expire the cache per-call or per-turn.
  • Do not inherit the cache into child tasks.
Record
GHSA-29r9-67vg-qj56
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L
Weakness
CWE-863
Updated
2026-11-02
OSVGHSA-r3xw-gcpr-rf26 6.9

Duplicate Advisory: PraisonAI: Human-in-the-loop tool approval is cached by tool name and silently reused for all subsequent calls with arbitrary arguments

Duplicate Advisory

This advisory has been withdrawn because it is a duplicate of GHSA-29r9-67vg-qj56. This link is maintained to preserve external references.

Original Description

PraisonAI before 1.6.78 caches tool approval decisions by tool name only, allowing attackers to reuse initial approvals for subsequent calls with arbitrary arguments. Attackers can exploit this by obtaining approval for a benign operation and then executing dangerous file write operations with unreviewed parameters in the same session.

Record
GHSA-r3xw-gcpr-rf26
CVSS 4.0
6.9 MediumCVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L
Weakness
CWE-863
Updated
2026-11-02
OSVPYSEC-2026-4265 6.1

PraisonAI: Human-in-the-loop tool approval is cached by tool name and silently reused for all subsequent calls with arbitrary arguments

Summary

PraisonAI gates dangerous tools (file writes, deletes, shell/code execution) behind an interactive approval prompt. The first approval of a tool is cached for the remainder of the run and silently reused for all later invocations of that tool with arbitrary, unreviewed arguments.

Root cause

ApprovalRegistry.is_already_approved (src/praisonai-agents/praisonaiagents/approval/registry.py, around line 181) returns True whenever the tool name is present in a per-run context set. The cache is keyed on tool name only — arguments are not part of the key.

approve_sync / approve_async (around lines 224-226 / 278-279) short-circuit on that cache before the approval backend is consulted.

clear_approved (around lines 186-187) is the only routine that clears the cache, but it is never invoked in the shipped library (only in tests). The cache persists for the entire agent run and is inherited by child tasks via contextvars.

Critical-tier tools (execute_command, execute_code) are exempt from the cache. But high-risk tools like write_file are not.

Proof of concept

from praisonaiagents.approval.registry import ApprovalRegistry
from praisonaiagents.approval.protocols import ApprovalDecision, ApprovalRequest

class CountingBackend:
    def __init__(self): self.prompts = []
    def request_approval_sync(self, request):
        self.prompts.append((request.tool_name, dict(request.arguments)))
        return ApprovalDecision(approved=True, reason="human approved")

backend = CountingBackend()
reg = ApprovalRegistry()
reg.set_backend(backend)
reg.add_requirement("write_file", "high")

d1 = reg.approve_sync("agent", "write_file", {"path": "/tmp/safe.txt", "content": "hi"})
# Human prompted — approves a benign write

d2 = reg.approve_sync("agent", "write_file", {"path": "/etc/crontab", "content": "* * * * * root evil"})
# NO prompt — auto-approved from cache

assert len(backend.prompts) == 1
assert d2.reason == "Already approved in context"

Negative control: execute_command (critical) re-prompts on every call — 2 prompts for 2 calls.

Impact

A write_file approval for a benign path authorizes every later write_file call in the session with arbitrary arguments. A model steered by malicious input can write to sensitive locations with no further human prompt.

Suggested fix

  • Include arguments in the approval cache key, or re-prompt on argument change.
  • Expire the cache per-call or per-turn.
  • Do not inherit the cache into child tasks.
Record
PYSEC-2026-4265
CVSS 3.1
6.1 MediumCVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:L
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
praisonaiagents
PyPI
through 1.6.77
1.6.78
praisonaiagents
PyPI
before 1.6.78, plus listed versions
0.0.10.0.100.0.1000.0.1010.0.102
Show 45 moreShow less
0.0.1030.0.1040.0.1050.0.1060.0.1070.0.1080.0.1090.0.110.0.1100.0.1110.0.1120.0.1130.0.1140.0.1150.0.1160.0.1170.0.1180.0.1190.0.120.0.1200.0.1210.0.1220.0.1230.0.1240.0.1250.0.1260.0.1270.0.1280.0.1290.0.130.0.1300.0.1310.0.1320.0.1330.0.1340.0.1350.0.1360.0.1370.0.1380.0.1390.0.140.0.1400.0.1410.0.1420.0.143
1.6.78

History

History
RecordedChangedSources
affected
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-60087 is a medium vulnerability (CVSS 6.9) in Mervinpraison Praisonai, published July 15, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.34%, the 27th percentile. Fixed in praisonaiagents 1.6.78.

References

This page doesn't list everything

Left out here: 554 versions. The JSON record has them.

MoveEnter Open