praisonai-platform: Any workspace member can delete the entire workspace via DELETE /workspaces/{id}
Description
Any member of a PraisonAI workspace can delete the entire workspace and all its data via the DELETE /workspaces/{id} endpoint due to an authorization bypass.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Any member of a PraisonAI workspace can delete the entire workspace and all its data via the DELETE /workspaces/{id} endpoint due to an authorization bypass.
Vulnerability
The DELETE /workspaces/{workspace_id} endpoint in src/praisonai-platform/praisonai_platform/api/routes/workspaces.py (lines 77–86) is protected only by Depends(require_workspace_member), which defaults to min_role="member" and is never overridden to require a higher privilege (e.g., owner). The dependency checks that the user is a member of the workspace but does not verify any role level before calling WorkspaceService.delete(), which performs a cascading delete of the workspace and all associated records (projects, issues, comments, agents, labels, members). No confirmation token, soft-delete, or recovery mechanism exists. This affects all versions up to and including the one disclosed in the advisory. [1][2]
Exploitation
An attacker needs only a valid session as any member of the target workspace (no special role required). The attacker sends a single HTTP DELETE request to /workspaces/{workspace_id} (with the workspace ID known or enumerable). No user interaction beyond the attacker's own action is needed; no race condition or additional privilege is required. The endpoint immediately executes the deletion. [1][2]
Impact
On success, the attacker causes complete and irreversible loss of the entire workspace: every project, issue, comment, agent, label, and member record is permanently deleted. This is a denial-of-service and data-loss event with no recovery path. The affected workspace owner loses all tenant data. [1][2]
Mitigation
The fix requires changing the dependency to require the owner role (e.g., Depends(require_workspace_member(min_role="owner"))) and ideally adding a confirmation mechanism (e.g., requiring the user to type the workspace name) and a soft-delete/recovery window. As of the advisory publication date (2026-06-01), the vendor has been notified but no patched version or workaround has been released in the available references. [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
1Patches
1b707fd0b27fbMerge pull request #171 from MervinPraison/develop
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("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')
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  ### Manual Model Output - \ No newline at end of file + + +## 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 addedpoetry.lock+1180 −1156 modifiedpraisonai/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 DELETE /workspaces/{workspace_id} endpoint uses require_workspace_member with the default min_role='member' instead of requiring the owner role, allowing any workspace member to delete the entire workspace."
Attack vector
An attacker who is a member of a workspace (holding a JWT with `role="member"`) sends a single `DELETE /workspaces/{workspace_id}` request with their bearer token. The `require_workspace_member` dependency passes because the default minimum role is `"member"`, allowing the request to reach `WorkspaceService.delete()`. SQLAlchemy cascade rules then remove the workspace row and every related row (members, projects, issues, comments, agents, labels). There is no owner-role gate, confirmation token, soft-delete window, or recovery path. [ref_id=1] [ref_id=2]
Affected code
**File:** `src/praisonai-platform/praisonai_platform/api/routes/workspaces.py`, lines 77-86; `services/workspace_service.py`'s `delete()` method. The route uses `Depends(require_workspace_member)` which defaults to `min_role="member"` and is never overridden. The service method `WorkspaceService.delete(workspace_id)` performs the destructive operation without any caller-permission verification. The role hierarchy (`MemberService.has_role`, member_service.py:80-96) is implemented but unused for this endpoint. [ref_id=1]
What the fix does
The patch introduces a new dependency `_require_workspace_owner` that calls `require_workspace_member` with `min_role="owner"`, and replaces the existing `Depends(require_workspace_member)` on the delete endpoint. This ensures only users with the `owner` role can invoke the destructive delete operation. Member-tier tokens now fail at the dependency gate, returning a 403 before the service layer is reached. [ref_id=1] [ref_id=2]
Preconditions
- configpraisonai-platform is deployed multi-tenant
- authAttacker has any membership token (role='member') in the target workspace
- networkAttacker can send HTTP DELETE requests to the API endpoint
Generated on Jun 1, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
2News mentions
0No linked articles in our index yet.