Skip to content

Commit f007639

Browse files
committed
Release v4.5.126
1 parent d0523d5 commit f007639

File tree

22 files changed

+258
-46
lines changed

22 files changed

+258
-46
lines changed

docker/Dockerfile.chat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=4.5.125" \
19+
"praisonai>=4.5.126" \
2020
"praisonai[chat]" \
2121
"embedchain[github,youtube]"
2222

docker/Dockerfile.dev

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
2020
# Install Python packages (using latest versions)
2121
RUN pip install --no-cache-dir \
2222
praisonai_tools \
23-
"praisonai>=4.5.125" \
23+
"praisonai>=4.5.126" \
2424
"praisonai[ui]" \
2525
"praisonai[chat]" \
2626
"praisonai[realtime]" \

docker/Dockerfile.ui

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
1616
# Install Python packages (using latest versions)
1717
RUN pip install --no-cache-dir \
1818
praisonai_tools \
19-
"praisonai>=4.5.125" \
19+
"praisonai>=4.5.126" \
2020
"praisonai[ui]" \
2121
"praisonai[crewai]"
2222

src/praisonai-agents/praisonaiagents/approval/registry.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ def mark_approved(self, tool_name: str) -> None:
147147
self._approved_context.set(approved)
148148

149149
def is_already_approved(self, tool_name: str) -> bool:
150+
if self.get_risk_level(tool_name) == "critical":
151+
return False
150152
return tool_name in self._approved_context.get(set())
151153

152154
def clear_approved(self) -> None:

src/praisonai-agents/praisonaiagents/tools/skill_tools.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ def run_skill_script(
125125
except Exception as e:
126126
return f"Error executing script: {str(e)}"
127127

128+
@require_approval(risk_level="low")
128129
def read_skill_file(
129130
self,
130131
skill_path: str,
@@ -149,6 +150,10 @@ def read_skill_file(
149150
skill_path = os.path.join(self._working_directory, skill_path)
150151
skill_path = os.path.abspath(skill_path)
151152

153+
working_dir = os.path.abspath(self._working_directory)
154+
if os.path.commonpath([skill_path, working_dir]) != working_dir:
155+
return f"Error: Workspace boundary violation - skill directory escapes workspace"
156+
152157
if not os.path.exists(skill_path):
153158
return f"Error: Skill directory not found at {skill_path}"
154159

@@ -160,7 +165,7 @@ def read_skill_file(
160165
full_path = os.path.abspath(full_path)
161166

162167
# Security check: ensure file is within skill directory
163-
if not full_path.startswith(skill_path):
168+
if os.path.commonpath([full_path, skill_path]) != skill_path:
164169
return f"Error: Path traversal detected - {file_path} is outside skill directory"
165170

166171
if not os.path.exists(full_path):
@@ -239,6 +244,7 @@ def run_skill_script(script_path: str, args: str = "", timeout: int = 60) -> str
239244
return _skill_tools.run_skill_script(script_path, args, timeout)
240245

241246

247+
@require_approval(risk_level="low")
242248
def read_skill_file(skill_path: str, file_path: str, encoding: str = 'utf-8') -> str:
243249
"""
244250
Read a file from a skill directory.

src/praisonai-agents/praisonaiagents/tools/web_crawl_tools.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,47 @@ def web_crawl(
204204
single_url = isinstance(urls, str)
205205
if single_url and ',' in urls:
206206
# LLM may pass comma-separated URLs as a single string
207-
url_list = [u.strip() for u in urls.split(',') if u.strip()]
208-
single_url = len(url_list) == 1
207+
raw_url_list = [u.strip() for u in urls.split(',') if u.strip()]
208+
single_url = len(raw_url_list) == 1
209209
else:
210-
url_list = [urls] if single_url else urls
210+
raw_url_list = [urls] if single_url else urls
211+
212+
# Validate URLs to prevent SSRF and Local File Read
213+
import urllib.parse
214+
import socket
215+
import ipaddress
216+
217+
url_list = []
218+
for u in raw_url_list:
219+
try:
220+
parsed = urllib.parse.urlparse(u)
221+
if parsed.scheme not in ('http', 'https'):
222+
logger.warning(f"Rejected non-http/https URL: {u}")
223+
continue
224+
hostname = parsed.hostname
225+
if not hostname:
226+
continue
227+
228+
# Allow opting out of SSRF protection for advanced use cases
229+
if os.environ.get("ALLOW_LOCAL_CRAWL") != "true":
230+
try:
231+
ip_str = socket.gethostbyname(hostname)
232+
ip = ipaddress.ip_address(ip_str)
233+
if ip.is_loopback or ip.is_private or ip.is_link_local or ip.is_multicast or ip.is_unspecified:
234+
logger.warning(f"Rejected SSRF or private IP attempt: {u}")
235+
continue
236+
except socket.gaierror:
237+
logger.warning(f"Could not resolve hostname for: {u}")
238+
continue
239+
240+
url_list.append(u)
241+
except Exception as e:
242+
logger.warning(f"URL validation failed for {u}: {e}")
243+
continue
244+
245+
if not url_list:
246+
return {"error": "No valid or safe URLs provided. Local and non-http(s) URLs are blocked for security."}
247+
211248

212249
# Get available providers
213250
available = _get_available_crawl_providers()

src/praisonai-agents/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "praisonaiagents"
7-
version = "1.5.125"
7+
version = "1.5.126"
88
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
99
readme = "README.md"
1010
requires-python = ">=3.10"

src/praisonai-agents/uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/praisonai/api.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ def _sanitize_html(html: str) -> str:
99
"""Sanitize HTML to prevent XSS from markdown-generated content."""
1010
return nh3.clean(html)
1111
except ImportError:
12-
def _sanitize_html(html: str) -> str:
13-
"""Fallback: no nh3, return as-is (install nh3 for XSS protection)."""
14-
return html
12+
def _sanitize_html(html_str: str) -> str:
13+
"""Fallback: no nh3, return escaped HTML. Install nh3 for rich HTML rendering."""
14+
import html
15+
return html.escape(html_str)
1516

1617
def basic():
1718
from praisonai import PraisonAI

src/praisonai/praisonai.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ class Praisonai < Formula
33

44
desc "AI tools for various AI applications"
55
homepage "https://github.com/MervinPraison/PraisonAI"
6-
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v4.5.125.tar.gz"
7-
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v4.5.125.tar.gz | shasum -a 256`.split.first
6+
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v4.5.126.tar.gz"
7+
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v4.5.126.tar.gz | shasum -a 256`.split.first
88
license "MIT"
99

1010
depends_on "python@3.11"

0 commit comments

Comments
 (0)