#11961: fix: exec tool wraps shebang scripts in heredoc to use correct interpreter
agents
stale
## Summary
Fixes #11724 - Exec tool cannot execute Python scripts with import statements.
- **Root cause**: When multiline scripts with a shebang (e.g. `#!/usr/bin/env python3`) are passed to the exec tool, all execution paths (`sh -c`, `bash -c`, Docker `sh -lc`) treat the shebang as a comment and interpret subsequent lines as shell commands. This causes Python's `import os` to invoke ImageMagick's `import` binary.
- **Fix**: Add `wrapScriptCommand()` in `node-shell.ts` that detects shebang-prefixed commands and wraps the script body in a single-quoted heredoc (`<<'EOF'`), so the shell delegates execution to the interpreter declared in the shebang line.
- Applied across all four exec paths: sandbox (Docker), PTY, PTY fallback, regular spawn, and node-host (`buildNodeShellCommand`).
### Before
```
sh -c '#!/usr/bin/env python3
import os # <-- executed as ImageMagick "import" command
print(os.getcwd()) # <-- shell error
'
```
### After
```
sh -c '/usr/bin/env python3 <<'\''OPENCLAW_SCRIPT_EOF'\''
import os
print(os.getcwd())
OPENCLAW_SCRIPT_EOF'
```
The heredoc uses a single-quoted marker to prevent shell variable expansion inside the script body. Non-shebang commands pass through unchanged.
## Test plan
- [x] Added unit tests for `wrapScriptCommand()` covering Python, Ruby, Node.js shebangs, edge cases (empty body, no shebang, `\r\n` line endings, shebang-only, leading whitespace)
- [x] Added integration test for `buildNodeShellCommand` with shebang-prefixed scripts
- [x] Existing `buildNodeShellCommand` tests pass unchanged (regular commands are not affected)
- [ ] Manual verification: run `exec` with a multiline Python script containing `import os`
- [ ] Verify Docker sandbox path handles shebang scripts correctly
Made with [Cursor](https://cursor.com)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR fixes execution of multi-line shebang scripts (e.g. Python with `import`) by adding `wrapScriptCommand()` in `src/infra/node-shell.ts` and applying it across exec paths (local spawn/PTY, Docker sandbox, and node-host via `buildNodeShellCommand`). It wraps shebang-prefixed commands into a single-quoted heredoc so the declared interpreter receives the script body instead of `/bin/sh` interpreting subsequent lines as shell commands.
Tests were added for `wrapScriptCommand()` and for `buildNodeShellCommand` behavior with a shebang script (`src/infra/node-shell.test.ts`).
<h3>Confidence Score: 3/5</h3>
- This PR is close to mergeable but has two correctness/safety issues in the new shebang-heredoc wrapping and approval/analysis consistency.
- The core approach is sound and well-tested, but (1) a fixed heredoc marker can be prematurely terminated by script content, and (2) node exec allowlist/approval analysis is performed on the unwrapped command while execution uses the wrapped command, which can invalidate approvals/allowlist matching and produce misleading audit logs for shebang scripts.
- src/infra/node-shell.ts, src/agents/bash-tools.exec.ts
<!-- greptile_other_comments_section -->
<sub>(5/5) You can turn off certain types of comments like style [here](https://app.greptile.com/review/github)!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#12871: fix: use bash and warn about shell injection (issue #12836)
by ambicuity · 2026-02-09
77.9%
#20177: fix(security): block command substitution in unquoted heredoc bodies
by orlyjamie · 2026-02-18
77.2%
#9200: Fix: Strip dangerous env vars from baseEnv in host execution
by vishaltandale00 · 2026-02-05
76.8%
#20640: fix: prevent zsh glob expansion errors in exec commands
by okuyam2y · 2026-02-19
76.8%
#18143: fix(windows): wrap shell builtins with cmd.exe /c for proper execution
by brandonwise · 2026-02-16
76.7%
#5168: Fix: force UTF-8 for Windows exec
by ManojINaik · 2026-01-31
76.4%
#12308: fix(cli): redirect log output to stderr during completion script ge...
by mcaxtr · 2026-02-09
76.1%
#9433: fix: pass raw command string to node exec instead of argv array
by dbottme · 2026-02-05
76.1%
#16525: fix(shell): stop rejecting newlines in double-quoted args (#16470)
by yinghaosang · 2026-02-14
75.7%
#18992: fix: suppress spurious tool error warnings for read-only exec commands
by Phineas1500 · 2026-02-17
75.5%