VYPR
High severity8.1GHSA Advisory· Published Jun 1, 2026· Updated Jun 1, 2026

praisonai-platform: Comment endpoints accept any issue_id without workspace ownership check, cross-workspace comment read and post IDOR

CVE-2026-47417

Description

Comment endpoints in PraisonAI platform fail to verify issue ownership, allowing cross-workspace reading and posting of comments.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Comment endpoints in PraisonAI platform fail to verify issue ownership, allowing cross-workspace reading and posting of comments.

Vulnerability

The comment endpoints POST /workspaces/{workspace_id}/issues/{issue_id}/comments and GET .../comments only check workspace membership via require_workspace_member(workspace_id) but then pass the user-supplied issue_id directly to CommentService without verifying that the issue belongs to the workspace. This affects versions in the affected code [1][2].

Exploitation

An attacker who is a legitimate member of any workspace can craft requests targeting issues in other workspaces by supplying a different issue_id. They can list all comments on any issue and post new comments, bypassing workspace boundaries [1][2].

Impact

The attacker gains unauthorized read access to all comments on any issue across all workspaces, and can inject arbitrary comments into any issue. This compromises confidentiality and integrity of issue discussions [1][2].

Mitigation

The fix requires validating that the issue_id belongs to the workspace before processing the comment. As per the advisory, the vendor was notified. No specific patch version is mentioned; users should apply the fix from the repository or wait for a patched release. If no patch is available, consider disabling the comment endpoints or adding manual validation [1][2].

AI Insight generated on Jun 1, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected products

1

Patches

2
8c4ab718aeeb

PraisonAI Call API Release

https://github.com/MervinPraison/PraisonAIMervinPraisonOct 17, 2024Fixed in 0.1.4via llm-release-walk
7 files changed · +43 14
  • Dockerfile+1 1 modified
    @@ -1,6 +1,6 @@
     FROM python:3.11-slim
     WORKDIR /app
     COPY . .
    -RUN pip install flask praisonai==0.1.3 gunicorn markdown
    +RUN pip install flask praisonai==0.1.4 gunicorn markdown
     EXPOSE 8080
     CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
    
  • docs/api/praisonai/deploy.html+1 1 modified
    @@ -110,7 +110,7 @@ <h2 id="raises">Raises</h2>
                 file.write(&#34;FROM python:3.11-slim\n&#34;)
                 file.write(&#34;WORKDIR /app\n&#34;)
                 file.write(&#34;COPY . .\n&#34;)
    -            file.write(&#34;RUN pip install flask praisonai==0.1.3 gunicorn markdown\n&#34;)
    +            file.write(&#34;RUN pip install flask praisonai==0.1.4 gunicorn markdown\n&#34;)
                 file.write(&#34;EXPOSE 8080\n&#34;)
                 file.write(&#39;CMD [&#34;gunicorn&#34;, &#34;-b&#34;, &#34;0.0.0.0:8080&#34;, &#34;api:app&#34;]\n&#39;)
                 
    
  • poetry.lock+20 2 modified
    @@ -6258,6 +6258,24 @@ cffi = ">=1.4.1"
     docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"]
     tests = ["hypothesis (>=3.27.0)", "pytest (>=3.2.1,!=3.3.0)"]
     
    +[[package]]
    +name = "pyngrok"
    +version = "7.2.0"
    +description = "A Python wrapper for ngrok."
    +optional = true
    +python-versions = ">=3.8"
    +files = [
    +    {file = "pyngrok-7.2.0-py3-none-any.whl", hash = "sha256:1e96ab1229736e2e030fa8975805ab1fa9e463178f83337fc07fdd2b4e8dbed6"},
    +    {file = "pyngrok-7.2.0.tar.gz", hash = "sha256:4e43af9b2f21ceed8d213797028fe8823003f185b49792e4d383302365c81515"},
    +]
    +
    +[package.dependencies]
    +PyYAML = ">=5.1"
    +
    +[package.extras]
    +dev = ["coverage[toml]", "flake8", "flake8-pyproject", "pep8-naming", "psutil"]
    +docs = ["Sphinx", "mypy", "sphinx-autodoc-typehints (==1.25.2)", "sphinx-notfound-page", "sphinx-substitution-extensions", "types-PyYAML"]
    +
     [[package]]
     name = "pyparsing"
     version = "3.2.0"
    @@ -8857,7 +8875,7 @@ type = ["pytest-mypy"]
     agentops = ["agentops"]
     anthropic = ["langchain-anthropic"]
     api = ["flask"]
    -call = ["fastapi", "flaml", "python-dotenv", "twilio", "typer", "uvicorn", "websockets"]
    +call = ["fastapi", "flaml", "pyngrok", "python-dotenv", "rich", "twilio", "typer", "uvicorn", "websockets"]
     chat = ["aiosqlite", "chainlit", "crawl4ai", "greenlet", "litellm", "tavily-python"]
     code = ["aiosqlite", "chainlit", "crawl4ai", "greenlet", "litellm", "tavily-python"]
     cohere = ["langchain-cohere"]
    @@ -8871,4 +8889,4 @@ ui = ["chainlit"]
     [metadata]
     lock-version = "2.0"
     python-versions = ">=3.10,<3.13"
    -content-hash = "74602750ef14d7040dad02842980b2eebbf0ac8c1f4324627602764578814a5a"
    +content-hash = "d246ccacd08ba3599a7b22e222e784396df2385dc76532b56e86bfccaf7522c0"
    
  • praisonai/api/call.py+16 6 modified
    @@ -10,6 +10,8 @@
     from dotenv import load_dotenv
     import typer
     import uvicorn
    +from pyngrok import ngrok
    +from rich import print
     
     load_dotenv()
     
    @@ -151,17 +153,26 @@ async def send_session_update(openai_ws):
         print('Sending session update:', json.dumps(session_update))
         await openai_ws.send(json.dumps(session_update))
     
    -def run_server(port: int):
    +def run_server(port: int, use_ngrok: bool = False):
         """Run the FastAPI server using uvicorn."""
    +    if use_ngrok:
    +        public_url = ngrok.connect(port).public_url
    +        # print(f"Ngrok tunnel established: {public_url}")
    +        print(f"Praison AI Voice URL: {public_url}/call")
    +    
         print(f"Starting Praison AI Call Server on port {port}...")
    -    uvicorn.run(app, host="0.0.0.0", port=port)
    +    uvicorn.run(app, host="0.0.0.0", port=port, log_level="warning")
     
     app_cli = typer.Typer()
     
     @app_cli.command()
    -def main(port: int = typer.Option(8090, help="Port to run the server on")):
    +def main(
    +    port: int = typer.Option(8090, help="Port to run the server on"),
    +    ngrok: bool = typer.Option(False, help="Use ngrok to expose the server")
    +):
         """Run the Praison AI Call Server."""
    -    print(f"Received port value: {port}")  # Debug print
    +    # print(f"Received port value: {port}")  # Debug print
    +    # print(f"Use ngrok: {ngrok}")  # Debug print
         
         # Extract the actual port value from the OptionInfo object
         if isinstance(port, typer.models.OptionInfo):
    @@ -170,9 +181,8 @@ def main(port: int = typer.Option(8090, help="Port to run the server on")):
             port_value = port
         
         port_int = int(port_value)
    -    print(f"Using port: {port_int}")  # Debug print
         
    -    run_server(port=port_int)
    +    run_server(port=port_int, use_ngrok=ngrok)
     
     if __name__ == "__main__":
         app_cli()
    
  • praisonai/deploy.py+1 1 modified
    @@ -56,7 +56,7 @@ def create_dockerfile(self):
                 file.write("FROM python:3.11-slim\n")
                 file.write("WORKDIR /app\n")
                 file.write("COPY . .\n")
    -            file.write("RUN pip install flask praisonai==0.1.3 gunicorn markdown\n")
    +            file.write("RUN pip install flask praisonai==0.1.4 gunicorn markdown\n")
                 file.write("EXPOSE 8080\n")
                 file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
                 
    
  • praisonai.rb+1 1 modified
    @@ -3,7 +3,7 @@ class Praisonai < Formula
       
         desc "AI tools for various AI applications"
         homepage "https://github.com/MervinPraison/PraisonAI"
    -    url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/0.1.3.tar.gz"
    +    url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/0.1.4.tar.gz"
         sha256 "1828fb9227d10f991522c3f24f061943a254b667196b40b1a3e4a54a8d30ce32"  # Replace with actual SHA256 checksum
         license "MIT"
       
    
  • pyproject.toml+3 2 modified
    @@ -1,6 +1,6 @@
     [tool.poetry]
     name = "PraisonAI"
    -version = "0.1.3"
    +version = "0.1.4"
     description = "PraisonAI application combines AutoGen and CrewAI or similar frameworks into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration."
     authors = ["Mervin Praison"]
     license = ""
    @@ -44,6 +44,7 @@ uvicorn = {version = ">=0.20.0", optional = true}
     python-dotenv = {version = ">=0.19.0", optional = true}
     typer = {version = ">=0.9.0", optional = true}
     flaml = {version = ">=2.3.1", extras = ["automl"], optional = true}
    +pyngrok = {version = ">=1.4.0", optional = true}
     
     [tool.poetry.group.docs.dependencies]
     mkdocs = "*"
    @@ -118,7 +119,7 @@ chat = ["chainlit", "litellm", "aiosqlite", "greenlet", "tavily-python", "crawl4
     code = ["chainlit", "litellm", "aiosqlite", "greenlet", "tavily-python", "crawl4ai"]
     train = ["setup-conda-env"]
     realtime = ["chainlit", "litellm", "aiosqlite", "greenlet", "tavily-python", "crawl4ai", "websockets", "plotly", "yfinance", "duckduckgo_search"]
    -call = ["twilio", "fastapi", "uvicorn", "websockets", "python-dotenv", "typer", "flaml"]
    +call = ["twilio", "fastapi", "uvicorn", "websockets", "python-dotenv", "typer", "flaml", "pyngrok", "rich"]
     
     [tool.poetry-dynamic-versioning]
     enable = true
    
b707fd0b27fb

Merge pull request #171 from MervinPraison/develop

https://github.com/MervinPraison/PraisonAIMervin PraisonOct 17, 2024Fixed in 0.1.4via release-tag
20 files changed · +8540 1214
  • Dockerfile+1 1 modified
    @@ -1,6 +1,6 @@
     FROM python:3.11-slim
     WORKDIR /app
     COPY . .
    -RUN pip install flask praisonai==0.1.3 gunicorn markdown
    +RUN pip install flask praisonai==0.1.4 gunicorn markdown
     EXPOSE 8080
     CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]
    
  • docs/api/praisonai/deploy.html+1 1 modified
    @@ -110,7 +110,7 @@ <h2 id="raises">Raises</h2>
                 file.write(&#34;FROM python:3.11-slim\n&#34;)
                 file.write(&#34;WORKDIR /app\n&#34;)
                 file.write(&#34;COPY . .\n&#34;)
    -            file.write(&#34;RUN pip install flask praisonai==0.1.3 gunicorn markdown\n&#34;)
    +            file.write(&#34;RUN pip install flask praisonai==0.1.4 gunicorn markdown\n&#34;)
                 file.write(&#34;EXPOSE 8080\n&#34;)
                 file.write(&#39;CMD [&#34;gunicorn&#34;, &#34;-b&#34;, &#34;0.0.0.0:8080&#34;, &#34;api:app&#34;]\n&#39;)
                 
    
  • docs/api-reference/index.mdx+22 0 added
    @@ -0,0 +1,22 @@
    +---
    +title: 'API Reference'
    +description: 'PraisonAI API documentation'
    +---
    +
    +{/* Replace any comments with this style */}
    +
    +# API Reference
    +
    +{/* Rest of the content remains the same */}
    +
    +This section provides detailed information about the PraisonAI API.
    +
    +## Modules
    +
    +- [praisonai](../api/praisonai/index)
    +- [praisonai.auto](../api/praisonai/auto)
    +- [praisonai.agents_generator](../api/praisonai/agents_generator)
    +- [praisonai.cli](../api/praisonai/cli)
    +- [praisonai.deploy](../api/praisonai/deploy)
    +
    +For more detailed API documentation, please refer to the generated files in the `api` folder.
    
  • docs/home.md+12 16 modified
    @@ -2,31 +2,27 @@
     
     <p align="center">
       <picture>
    -    <source media="(prefers-color-scheme: dark)" srcset="images/praisonai-logo-large.png">
    -    <source media="(prefers-color-scheme: light)" srcset="images/praisonai-logo-large.png">
    -    <img alt="PraisonAI Logo" src="images/praisonai-logo-large.png">
    +    <source media="(prefers-color-scheme: dark)" srcset="/logo/dark.png" />
    +    <source media="(prefers-color-scheme: light)" srcset="/logo/light.png" />
    +    <img alt="PraisonAI Logo" src="/logo/light.png" style={{display: "block", margin: "auto"}} />
       </picture>
     </p>
     
     <p align="center">
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://static.pepy.tech/badge/PraisonAI" alt="Total Downloads"></a>
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/github/v/release/MervinPraison/PraisonAI" alt="Latest Stable Version"></a>
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License"></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://static.pepy.tech/badge/PraisonAI" alt="Total Downloads" /></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/github/v/release/MervinPraison/PraisonAI" alt="Latest Stable Version" /></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License" /></a>
     </p>
     
    -<div align="center">
    -
     # Praison AI
     
    -</div>
    -
     Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, represents a low-code, centralised framework designed to simplify the creation and orchestration of multi-agent systems for various LLM applications, emphasizing ease of use, customization, and human-agent interaction.
     
     <div align="center">
       <picture>
    -    <source media="(prefers-color-scheme: dark)" srcset="images/architecture-dark.png">
    -    <source media="(prefers-color-scheme: light)" srcset="images/architecture-light.png">
    -    <img alt="PraisonAI Architecture" src="images/architecture-light.png">
    +    <source media="(prefers-color-scheme: dark)" srcset="images/architecture-dark.png" />
    +    <source media="(prefers-color-scheme: light)" srcset="images/architecture-light.png" />
    +    <img alt="PraisonAI Architecture" src="images/architecture-light.png" />
       </picture>
     </div>
     
    @@ -42,8 +38,8 @@ Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, rep
     
     |               | Cookbook        | Open in Colab                                                                                                                                                                                                                                  |
     | ------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    -| Basic         | PraisonAI       | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>       |
    -| Include Tools | PraisonAI Tools | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-tools-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a> |
    +| Basic         | PraisonAI       | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" /></a>       |
    +| Include Tools | PraisonAI Tools | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-tools-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" /></a> |
     
     ## Install
     
    @@ -109,4 +105,4 @@ praisonai --framework autogen
     
     ```bash
     praisonai --auto create a movie script about Dog in Moon
    -```
    \ No newline at end of file
    +```
    
  • docs/index.md+10 20 modified
    @@ -1,30 +1,20 @@
     # Praison AI
     
    -<p align="center">
    -  <picture>
    -    <source media="(prefers-color-scheme: dark)" srcset="overrides/images/praisonai-logo-dark.png">
    -    <source media="(prefers-color-scheme: light)" srcset="overrides/images/praisonai-logo-light.png">
    -    <img alt="PraisonAI Logo" src="overrides/images/praisonai-logo-light.png">
    -  </picture>
    -</p>
    +<img alt="PraisonAI Logo" src="overrides/images/praisonai-logo-light.png" style="display: block; margin: auto;" />
     
     <p align="center">
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://static.pepy.tech/badge/PraisonAI" alt="Total Downloads"></a>
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/github/v/release/MervinPraison/PraisonAI" alt="Latest Stable Version"></a>
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License"></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://static.pepy.tech/badge/PraisonAI" alt="Total Downloads" /></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/github/v/release/MervinPraison/PraisonAI" alt="Latest Stable Version" /></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License" /></a>
     </p>
     
    -<div align="center">
    -
    -</div>
    -
     Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, represents a low-code, centralised framework designed to simplify the creation and orchestration of multi-agent systems for various LLM applications, emphasizing ease of use, customization, and human-agent interaction.
     
     <div align="center">
       <picture>
    -    <source media="(prefers-color-scheme: dark)" srcset="images/architecture-dark.png">
    -    <source media="(prefers-color-scheme: light)" srcset="images/architecture-light.png">
    -    <img alt="PraisonAI Architecture" src="images/architecture-dark.png">
    +    <source media="(prefers-color-scheme: dark)" srcset="images/architecture-dark.png" />
    +    <source media="(prefers-color-scheme: light)" srcset="images/architecture-light.png" />
    +    <img alt="PraisonAI Architecture" src="images/architecture-light.png" />
       </picture>
     </div>
     
    @@ -40,8 +30,8 @@ Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, rep
     
     |               | Cookbook        | Open in Colab                                                                                                                                                                                                                                  |
     | ------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    -| Basic         | PraisonAI       | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>       |
    -| Include Tools | PraisonAI Tools | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-tools-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a> |
    +| Basic         | PraisonAI       | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" /></a>       |
    +| Include Tools | PraisonAI Tools | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-tools-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" /></a> |
     
     ## Install
     
    @@ -79,4 +69,4 @@ praisonai --init create a movie script about dog in moon
     ## Run
     ```bash
     praisonai
    -```
    \ No newline at end of file
    +```
    
  • docs/introduction.md+28 0 added
    @@ -0,0 +1,28 @@
    +---
    +title: 'Introduction to PraisonAI'
    +description: 'Get started with PraisonAI, an intelligent AI-powered tool'
    +---
    +
    +# Introduction to PraisonAI
    +
    +Welcome to PraisonAI documentation! PraisonAI is a low-code, centralized framework designed to simplify the creation and orchestration of multi-agent systems for various LLM applications, emphasizing ease of use, customization, and human-agent interaction.
    +
    +## Key Features
    +
    +- Leverages both AutoGen and CrewAI
    +- Simplifies multi-agent system creation
    +- Emphasizes ease of use and customization
    +- Supports human-agent interaction
    +
    +## Getting Started
    +
    +To get started with PraisonAI, check out our [Installation](./installation) guide.
    +
    +For a quick overview, see our [TL;DR](./tldr) page.
    +
    +## Explore Further
    +
    +- [User Interface](./ui/ui)
    +- [Models](./models)
    +- [Tools](./tools)
    +- [API Reference](./api-reference)
    
  • docs/ui/ui.md+6 3 modified
    @@ -8,8 +8,7 @@
     | **Chat** | Chat with 100+ LLMs, single AI Agent | [https://docs.praison.ai/ui/chat](https://docs.praison.ai/ui/chat) |
     | **Code** | Chat with entire Codebase, single AI Agent | [https://docs.praison.ai/ui/code](https://docs.praison.ai/ui/code) |
     
    -## Chainlit
    -```bash
    +## Chainlit```bash
     pip install -U "praisonai[ui]"
     export OPENAI_API_KEY="Enter your API key"
     chainlit create-secret
    @@ -88,4 +87,8 @@ streamlit run app.py
     ![Run Agents](../images/ui-step-8.png)
     
     ### Manual Model Output
    -![Manual Model Output](../images/ui-step-11.png)
    \ No newline at end of file
    +![Manual Model Output](../images/ui-step-11.png)
    +
    +## PraisonAI Call
    +
    +To use the PraisonAI Call feature:
    
  • eslint.config.mjs+18 0 added
    @@ -0,0 +1,18 @@
    +import globals from "globals";
    +import * as mdx from 'eslint-plugin-mdx';
    +
    +export default [
    +  {
    +    files: ["**/*.{md,mdx}"],
    +    processor: mdx.createRemarkProcessor({
    +      lintCodeBlocks: true,
    +    }),
    +    languageOptions: {
    +      globals: globals.browser,
    +    },
    +    rules: {
    +      'no-var': 'error',
    +      'prefer-const': 'error',
    +    },
    +  },
    +];
    
  • .eslintrc+10 0 added
    @@ -0,0 +1,10 @@
    +{
    +    "extends": ["plugin:mdx/recommended"],
    +    // optional, if you want to lint code blocks at the same time
    +    "settings": {
    +      "mdx/code-blocks": true,
    +      // optional, if you want to disable language mapper, set it to `false`
    +      // if you want to override the default language mapper inside, you can provide your own
    +      "mdx/language-mapper": {}
    +    }
    +  }
    \ No newline at end of file
    
  • .gitignore+4 1 modified
    @@ -54,4 +54,7 @@ crewAI
     .venv
     
     # Credentials
    -credentials.json
    \ No newline at end of file
    +credentials.json
    +
    +# node_modules
    +node_modules
    
  • mint.json+109 0 added
    @@ -0,0 +1,109 @@
    +{
    +  "name": "PraisonAI Documentation",
    +  "logo": {
    +    "light": "/docs/images/praisonai-logo-black-large.png",
    +    "dark": "/docs/images/praisonai-logo-large.png"
    +  },
    +  "favicon": "/docs/images/favicon.png",
    +  "colors": {
    +    "primary": "#0069ED",
    +    "light": "#4D9CFF",
    +    "dark": "#0050B4"
    +  },
    +  "topbarLinks": [
    +    {
    +      "name": "GitHub",
    +      "url": "https://github.com/MervinPraison/PraisonAI"
    +    }
    +  ],
    +  "topbarCtaButton": {
    +    "name": "Get Started",
    +    "url": "https://docs.praison.ai/installation"
    +  },
    +  "navigation": [
    +    {
    +      "group": "Getting Started",
    +      "pages": [
    +        "introduction",
    +        "tldr",
    +        "installation",
    +        "initialise",
    +        "run",
    +        "auto"
    +      ]
    +    },
    +    {
    +      "group": "User Interface",
    +      "pages": [
    +        "ui/ui",
    +        "ui/chat",
    +        "ui/code",
    +        "ui/realtime"
    +      ]
    +    },
    +    {
    +      "group": "Core Concepts",
    +      "pages": [
    +        "train",
    +        "framework/crewai",
    +        "framework/autogen"
    +      ]
    +    },
    +    {
    +      "group": "Models",
    +      "pages": [
    +        "models",
    +        "models/openai",
    +        "models/groq",
    +        "models/google",
    +        "models/anthropic",
    +        "models/cohere",
    +        "models/mistral",
    +        "models/openrouter",
    +        "models/ollama",
    +        "models/other"
    +      ]
    +    },
    +    {
    +      "group": "Tools",
    +      "pages": [
    +        "tools",
    +        "tools/custom",
    +        "tools/gpt",
    +        "tools/duckduckgo",
    +        "tools/langchain",
    +        "firecrawl",
    +        "tools/wikipedia",
    +        "tools/youtube",
    +        "tools/tavily",
    +        "tools/reddit",
    +        "tools/you.com",
    +        "tools/crawl4ai",
    +        "tools/mem0"
    +      ]
    +    },
    +    {
    +      "group": "Monitoring",
    +      "pages": ["monitoring/agentops"]
    +    },
    +    {
    +      "group": "Developers",
    +      "pages": [
    +        "developers/test",
    +        "developers/agents-playbook",
    +        "developers/wrapper",
    +        "developers/wrapper-tools",
    +        "developers/googlecolab",
    +        "developers/googlecolab-tools",
    +        "deploy"
    +      ]
    +    },
    +    {
    +      "group": "API Reference",
    +      "pages": ["api-reference/index"]
    +    }
    +  ],
    +  "footerSocials": {
    +    "github": "https://github.com/MervinPraison/PraisonAI"
    +  }
    +}
    
  • package.json+9 0 added
    @@ -0,0 +1,9 @@
    +{
    +  "devDependencies": {
    +    "eslint": "^8.57.1",
    +    "eslint-plugin-mdx": "^3.1.5",
    +    "eslint-plugin-react": "^7.37.1",
    +    "globals": "^15.11.0",
    +    "typescript-eslint": "^8.8.1"
    +  }
    +}
    
  • package-lock.json+6906 0 added
  • poetry.lock+1180 1156 modified
  • praisonai/api/call.py+188 0 added
    @@ -0,0 +1,188 @@
    +import os
    +import json
    +import base64
    +import asyncio
    +import websockets
    +from fastapi import FastAPI, WebSocket, Request
    +from fastapi.responses import HTMLResponse
    +from fastapi.websockets import WebSocketDisconnect
    +from twilio.twiml.voice_response import VoiceResponse, Connect, Say, Stream
    +from dotenv import load_dotenv
    +import typer
    +import uvicorn
    +from pyngrok import ngrok
    +from rich import print
    +
    +load_dotenv()
    +
    +# Configuration
    +OPENAI_API_KEY = os.getenv('OPENAI_API_KEY') # requires OpenAI Realtime API Access
    +PORT = int(os.getenv('PORT', 8090))
    +SYSTEM_MESSAGE = (
    +    "You are a helpful and bubbly AI assistant who loves to chat about "
    +    "anything the user is interested in and is prepared to offer them facts. "
    +    "You have a penchant for dad jokes, owl jokes, and rickrolling – subtly. "
    +    "Always stay positive, but work in a joke when appropriate."
    +)
    +VOICE = 'alloy'
    +LOG_EVENT_TYPES = [
    +    'response.content.done', 'rate_limits.updated', 'response.done',
    +    'input_audio_buffer.committed', 'input_audio_buffer.speech_stopped',
    +    'input_audio_buffer.speech_started', 'session.created'
    +]
    +
    +app = FastAPI()
    +
    +if not OPENAI_API_KEY:
    +    raise ValueError('Missing the OpenAI API key. Please set it in the .env file.')
    +
    +@app.get("/", response_class=HTMLResponse)
    +async def index_page():
    +    return """
    +    <html>
    +        <head>
    +            <title>Praison AI Call Server</title>
    +        </head>
    +        <body>
    +            <h1>Praison AI Call Server is running!</h1>
    +        </body>
    +    </html>
    +    """
    +
    +@app.api_route("/call", methods=["GET", "POST"])
    +async def handle_incoming_call(request: Request):
    +    """Handle incoming call and return TwiML response to connect to Media Stream."""
    +    response = VoiceResponse()
    +    response.say("")
    +    response.pause(length=1)
    +    response.say("O.K. you can start talking!")
    +    host = request.url.hostname
    +    connect = Connect()
    +    connect.stream(url=f'wss://{host}/media-stream')
    +    response.append(connect)
    +    return HTMLResponse(content=str(response), media_type="application/xml")
    +
    +@app.websocket("/media-stream")
    +async def handle_media_stream(websocket: WebSocket):
    +    """Handle WebSocket connections between Twilio and OpenAI."""
    +    print("Client connected")
    +    await websocket.accept()
    +
    +    async with websockets.connect(
    +        'wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01',
    +        extra_headers={
    +            "Authorization": f"Bearer {OPENAI_API_KEY}",
    +            "OpenAI-Beta": "realtime=v1"
    +        }
    +    ) as openai_ws:
    +        await send_session_update(openai_ws)
    +        stream_sid = None
    +
    +        async def receive_from_twilio():
    +            """Receive audio data from Twilio and send it to the OpenAI Realtime API."""
    +            nonlocal stream_sid
    +            try:
    +                async for message in websocket.iter_text():
    +                    data = json.loads(message)
    +                    if data['event'] == 'media' and openai_ws.open:
    +                        audio_append = {
    +                            "type": "input_audio_buffer.append",
    +                            "audio": data['media']['payload']
    +                        }
    +                        await openai_ws.send(json.dumps(audio_append))
    +                    elif data['event'] == 'start':
    +                        stream_sid = data['start']['streamSid']
    +                        print(f"Incoming stream has started {stream_sid}")
    +            except WebSocketDisconnect:
    +                print("Client disconnected.")
    +                if openai_ws.open:
    +                    await openai_ws.close()
    +
    +        async def send_to_twilio():
    +            """Receive events from the OpenAI Realtime API, send audio back to Twilio."""
    +            nonlocal stream_sid
    +            try:
    +                async for openai_message in openai_ws:
    +                    response = json.loads(openai_message)
    +                    if response['type'] in LOG_EVENT_TYPES:
    +                        print(f"Received event: {response['type']}", response)
    +                    if response['type'] == 'session.updated':
    +                        print("Session updated successfully:", response)
    +                    if response['type'] == 'response.audio.delta' and response.get('delta'):
    +                        # Audio from OpenAI
    +                        try:
    +                            audio_payload = base64.b64encode(base64.b64decode(response['delta'])).decode('utf-8')
    +                            audio_delta = {
    +                                "event": "media",
    +                                "streamSid": stream_sid,
    +                                "media": {
    +                                    "payload": audio_payload
    +                                }
    +                            }
    +                            await websocket.send_json(audio_delta)
    +                        except Exception as e:
    +                            print(f"Error processing audio data: {e}")
    +            except Exception as e:
    +                print(f"Error in send_to_twilio: {e}")
    +
    +        await asyncio.gather(receive_from_twilio(), send_to_twilio())
    +
    +async def send_session_update(openai_ws):
    +    """Send session update to OpenAI WebSocket."""
    +    session_update = {
    +        "type": "session.update",
    +        "session": {
    +            "turn_detection": {
    +                "type": "server_vad",
    +                "threshold": 0.5,
    +                "prefix_padding_ms": 300,
    +                "silence_duration_ms": 200
    +            },
    +            "input_audio_format": "g711_ulaw",
    +            "output_audio_format": "g711_ulaw",
    +            # "input_audio_transcription": { "model": 'whisper-1' },
    +            # "transcription_models": [{"model": "whisper-1"}],
    +            "voice": VOICE,
    +            "tools": [],
    +            "tool_choice": "auto",
    +            "instructions": SYSTEM_MESSAGE,
    +            "modalities": ["text", "audio"],
    +            "temperature": 0.8
    +        }
    +    }
    +    print('Sending session update:', json.dumps(session_update))
    +    await openai_ws.send(json.dumps(session_update))
    +
    +def run_server(port: int, use_ngrok: bool = False):
    +    """Run the FastAPI server using uvicorn."""
    +    if use_ngrok:
    +        public_url = ngrok.connect(port).public_url
    +        # print(f"Ngrok tunnel established: {public_url}")
    +        print(f"Praison AI Voice URL: {public_url}/call")
    +    
    +    print(f"Starting Praison AI Call Server on port {port}...")
    +    uvicorn.run(app, host="0.0.0.0", port=port, log_level="warning")
    +
    +app_cli = typer.Typer()
    +
    +@app_cli.command()
    +def main(
    +    port: int = typer.Option(8090, help="Port to run the server on"),
    +    ngrok: bool = typer.Option(False, help="Use ngrok to expose the server")
    +):
    +    """Run the Praison AI Call Server."""
    +    # print(f"Received port value: {port}")  # Debug print
    +    # print(f"Use ngrok: {ngrok}")  # Debug print
    +    
    +    # Extract the actual port value from the OptionInfo object
    +    if isinstance(port, typer.models.OptionInfo):
    +        port_value = port.default
    +    else:
    +        port_value = port
    +    
    +    port_int = int(port_value)
    +    
    +    run_server(port=port_int, use_ngrok=ngrok)
    +
    +if __name__ == "__main__":
    +    app_cli()
    
  • praisonai/cli.py+10 1 modified
    @@ -16,6 +16,8 @@
     import shutil
     import subprocess
     import logging
    +import importlib
    +import praisonai.api.call as call_module
     logging.basicConfig(level=os.environ.get('LOGLEVEL', 'INFO'), format='%(asctime)s - %(levelname)s - %(message)s')
     
     try:
    @@ -134,6 +136,10 @@ def main(self):
                 self.create_realtime_interface()
                 return
             
    +        if getattr(args, 'call', False):
    +            call_module.main()
    +            return
    +        
             if args.agent_file == 'train':
                 package_root = os.path.dirname(os.path.abspath(__file__))
                 config_yaml_destination = os.path.join(os.getcwd(), 'config.yaml')
    @@ -261,6 +267,7 @@ def parse_args(self):
             parser.add_argument("--ollama", type=str, help="Ollama model name")
             parser.add_argument("--dataset", type=str, help="Dataset name for training", default="yahma/alpaca-cleaned")
             parser.add_argument("--realtime", action="store_true", help="Start the realtime voice interaction interface")
    +        parser.add_argument("--call", action="store_true", help="Start the PraisonAI Call server")
             args, unknown_args = parser.parse_known_args()
     
             if unknown_args and unknown_args[0] == '-b' and unknown_args[1] == 'api:app':
    @@ -277,6 +284,8 @@ def parse_args(self):
                 args.code = True
             if args.agent_file == 'realtime':
                 args.realtime = True
    +        if args.agent_file == 'call':
    +            args.call = True
     
             return args
         
    @@ -448,4 +457,4 @@ def create_realtime_interface(self):
     
     if __name__ == "__main__":
         praison_ai = PraisonAI()
    -    praison_ai.main()
    \ No newline at end of file
    +    praison_ai.main()
    
  • praisonai/deploy.py+1 1 modified
    @@ -56,7 +56,7 @@ def create_dockerfile(self):
                 file.write("FROM python:3.11-slim\n")
                 file.write("WORKDIR /app\n")
                 file.write("COPY . .\n")
    -            file.write("RUN pip install flask praisonai==0.1.3 gunicorn markdown\n")
    +            file.write("RUN pip install flask praisonai==0.1.4 gunicorn markdown\n")
                 file.write("EXPOSE 8080\n")
                 file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
                 
    
  • praisonai.rb+1 1 modified
    @@ -3,7 +3,7 @@ class Praisonai < Formula
       
         desc "AI tools for various AI applications"
         homepage "https://github.com/MervinPraison/PraisonAI"
    -    url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/0.1.3.tar.gz"
    +    url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/0.1.4.tar.gz"
         sha256 "1828fb9227d10f991522c3f24f061943a254b667196b40b1a3e4a54a8d30ce32"  # Replace with actual SHA256 checksum
         license "MIT"
       
    
  • pyproject.toml+11 2 modified
    @@ -1,6 +1,6 @@
     [tool.poetry]
     name = "PraisonAI"
    -version = "0.1.3"
    +version = "0.1.4"
     description = "PraisonAI application combines AutoGen and CrewAI or similar frameworks into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customization, and efficient human-agent collaboration."
     authors = ["Mervin Praison"]
     license = ""
    @@ -38,6 +38,13 @@ websockets = {version = ">=12.0", optional = true}
     plotly = {version = ">=5.24.0", optional = true}
     yfinance = {version = ">=0.2.44", optional = true}
     duckduckgo_search = {version = ">=6.3.0", optional = true}
    +twilio = {version = ">=7.0.0", optional = true}
    +fastapi = {version = ">=0.95.0", optional = true}
    +uvicorn = {version = ">=0.20.0", optional = true}
    +python-dotenv = {version = ">=0.19.0", optional = true}
    +typer = {version = ">=0.9.0", optional = true}
    +flaml = {version = ">=2.3.1", extras = ["automl"], optional = true}
    +pyngrok = {version = ">=1.4.0", optional = true}
     
     [tool.poetry.group.docs.dependencies]
     mkdocs = "*"
    @@ -97,6 +104,7 @@ build-backend = "poetry.core.masonry.api"
     praisonai = "praisonai.__main__:main"
     setup-conda-env = "setup.setup_conda_env:main"
     post-install = "setup.post_install:main"
    +praisonai-call = "praisonai.api.call:main"
     
     [tool.poetry.extras]
     ui = ["chainlit"]
    @@ -111,6 +119,7 @@ chat = ["chainlit", "litellm", "aiosqlite", "greenlet", "tavily-python", "crawl4
     code = ["chainlit", "litellm", "aiosqlite", "greenlet", "tavily-python", "crawl4ai"]
     train = ["setup-conda-env"]
     realtime = ["chainlit", "litellm", "aiosqlite", "greenlet", "tavily-python", "crawl4ai", "websockets", "plotly", "yfinance", "duckduckgo_search"]
    +call = ["twilio", "fastapi", "uvicorn", "websockets", "python-dotenv", "typer", "flaml", "pyngrok", "rich"]
     
     [tool.poetry-dynamic-versioning]
     enable = true
    @@ -119,4 +128,4 @@ style = "semver"
     
     [tool.poetry.build]
     generate-setup-file = false
    -script = "praisonai/setup/post_install.py"
    \ No newline at end of file
    +script = "praisonai/setup/post_install.py"
    
  • README.md+13 11 modified
    @@ -1,15 +1,15 @@
     <p align="center">
       <picture>
    -    <source media="(prefers-color-scheme: dark)" srcset="docs/images/praisonai-logo-large.png">
    -    <source media="(prefers-color-scheme: light)" srcset="docs/images/praisonai-logo-black-large.png">
    -    <img alt="PraisonAI Logo" src="docs/images/praisonai-logo-black-large.png">
    +    <source media="(prefers-color-scheme: dark)" srcset="docs/logo/dark.png" />
    +    <source media="(prefers-color-scheme: light)" srcset="docs/logo/light.png" />
    +    <img alt="PraisonAI Logo" src="docs/logo/light.png" />
       </picture>
     </p>
     
     <p align="center">
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://static.pepy.tech/badge/PraisonAI" alt="Total Downloads"></a>
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/github/v/release/MervinPraison/PraisonAI" alt="Latest Stable Version"></a>
    -<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License"></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://static.pepy.tech/badge/PraisonAI" alt="Total Downloads" /></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/github/v/release/MervinPraison/PraisonAI" alt="Latest Stable Version" /></a>
    +<a href="https://github.com/MervinPraison/PraisonAI"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License" /></a>
     </p>
     
     <div align="center">
    @@ -22,9 +22,9 @@ Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, rep
     
     <div align="center">
       <picture>
    -    <source media="(prefers-color-scheme: dark)" srcset="docs/images/architecture-dark.png">
    -    <source media="(prefers-color-scheme: light)" srcset="docs/images/architecture-light.png">
    -    <img alt="PraisonAI Architecture" src="docs/images/architecture-light.png">
    +    <source media="(prefers-color-scheme: dark)" srcset="docs/images/architecture-dark.png" />
    +    <source media="(prefers-color-scheme: light)" srcset="docs/images/architecture-light.png" />
    +    <img alt="PraisonAI Architecture" src="docs/images/architecture-light.png" />
       </picture>
     </div>
     
    @@ -46,8 +46,8 @@ Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, rep
     
     |               | Cookbook        | Open in Colab                                                                                                                                                                                                                                  |
     | ------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    -| Basic         | PraisonAI       | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a>       |
    -| Include Tools | PraisonAI Tools | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-tools-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/></a> |
    +| Basic         | PraisonAI       | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" /></a>       |
    +| Include Tools | PraisonAI Tools | <a target="_blank" href="https://colab.research.google.com/github/MervinPraison/PraisonAI/blob/main/cookbooks/praisonai-tools-googlecolab.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab" /></a> |
     
     ## Install
     
    @@ -58,6 +58,7 @@ Praison AI, leveraging both AutoGen and CrewAI or any other agent framework, rep
     | **PraisonAI Chat** | `pip install "praisonai[chat]"` |
     | **PraisonAI Train** | `pip install "praisonai[train]"` |
     | **PraisonAI Realtime** | `pip install "praisonai[realtime]"` |
    +| **PraisonAI Call** | `pip install "praisonai[call]"` |
     
     ## Key Features
     
    @@ -324,3 +325,4 @@ This configuration ensures that your development dependencies are correctly cate
     ## License
     
     Praison AI is an open-sourced software licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.
    +
    

Vulnerability mechanics

Root cause

"The route layer gates access on workspace membership but never verifies that the URL-supplied issue_id belongs to that workspace, allowing cross-workspace comment read and write."

Attack vector

An attacker who is a member of any workspace can read every comment on, and post new comments to, any issue in any other workspace. The attacker harvests a target issue UUID from side channels (activity feed, webhooks, cross-workspace links) and sends `GET /workspaces/{attacker_workspace}/issues/{target_issue}/comments` or `POST` with a comment body. The membership check passes because the attacker controls the workspace in the URL path, and `CommentService` never confirms the issue belongs to that workspace [CWE-639].

Affected code

The vulnerability is in `src/praisonai-platform/praisonai_platform/api/routes/issues.py`, lines 143-171, and `src/praisonai-platform/praisonai_platform/services/comment_service.py`, lines 19-53. The `add_comment` and `list_comments` route handlers gate access via `require_workspace_member(workspace_id)` but then pass the URL-supplied `issue_id` directly to `CommentService.create()` and `CommentService.list_for_issue()` without verifying that the issue belongs to the workspace. The service methods query or write comments using only `issue_id` with no workspace join.

What the fix does

The suggested fix adds a `_require_issue_in_workspace` helper that resolves the issue scoped to `workspace_id` before dispatching to `CommentService`. This ensures that if the issue does not belong to the workspace, a 404 is returned, preventing both unauthorized reads and writes. The fix is applied at the route layer in `issues.py` and does not change the `CommentService` signature.

Preconditions

  • configpraisonai-platform is deployed multi-tenant
  • authAttacker has any workspace membership token
  • inputTarget issue UUID is known or guessable

Generated on Jun 1, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

2

News mentions

0

No linked articles in our index yet.