Release v0.0.52 - #297
Release v0.0.52#297
Conversation
Strix Security ReviewWarning This pull request has 7 commits after the last Strix review ( 1 open security finding on this PR:
Review summaryReviewed all 27 changed files in PR #297 (release v0.0.52), inlined into the manifest. The change set primarily adds REPL/UX features (kill-ring, Fixed the findings? re-run the review, or tag Updated for Reviewed by Strix |
3c23e72 to
d14c5ad
Compare
| let exec (s: Spec) : unit = | ||
| // the same boundary spawn enforces [D:spawn-nul-funnel] |
There was a problem hiding this comment.
🟢 exec reifier bypasses the plan runtime guard on POSIX, executing a command inside a dry-run plan
Severity: LOW
The new cmd | exec process-replacement reifier (Proc.exec) reproduces the NUL-byte refusal boundary of Proc.spawn but omits the runtime plan guard. On POSIX it calls execvp directly without checking Session.planGuardActive(), so an indirect command inside a plan block (a helper function that itself invokes exec) runs and replaces the process instead of being refused.
| let exec (s: Spec) : unit = | |
| // the same boundary spawn enforces [D:spawn-nul-funnel] | |
| let exec (s: Spec) : unit = | |
| // runtime plan refusal [D:plan-proc-runtime-guard]: process replacement | |
| // must obey the same boundary spawn enforces — POSIX execvp does not | |
| // funnel through spawn, so the guard is applied here directly. | |
| if Session.planGuardActive () then | |
| failwith | |
| $"'{s.Prog}' runs a command, and 'proc' is refused inside 'plan' — a spawned binary reads and writes opaquely, so its effects cannot be captured; plan covers weir-native mutation only (File/Dir/Http)" | |
| // the same boundary spawn enforces [D:spawn-nul-funnel] |
Prompt to fix with AI
This is a security vulnerability found during a code review.
Vulnerability: `exec` reifier bypasses the `plan` runtime guard on POSIX, executing a command inside a dry-run plan
Severity: LOW
The new `cmd | exec` process-replacement reifier (`Proc.exec`) reproduces the NUL-byte refusal boundary of `Proc.spawn` but omits the runtime `plan` guard. On POSIX it calls `execvp` directly without checking `Session.planGuardActive()`, so an *indirect* command inside a `plan` block (a helper function that itself invokes `exec`) runs and replaces the process instead of being refused.
Location: src/Weir/Proc.fs:311-312
Context: Add plan-guard refusal at the top of exec
```
// Before:
let exec (s: Spec) : unit =
// the same boundary spawn enforces [D:spawn-nul-funnel]
// After:
let exec (s: Spec) : unit =
// runtime plan refusal [D:plan-proc-runtime-guard]: process replacement
// must obey the same boundary spawn enforces — POSIX execvp does not
// funnel through spawn, so the guard is applied here directly.
if Session.planGuardActive () then
failwith
$"'{s.Prog}' runs a command, and 'proc' is refused inside 'plan' — a spawned binary reads and writes opaquely, so its effects cannot be captured; plan covers weir-native mutation only (File/Dir/Http)"
// the same boundary spawn enforces [D:spawn-nul-funnel]
```
How to fix:
Add the same runtime plan refusal that `Proc.spawn` performs at the entry of `Proc.exec`, before argv/env processing and before the platform split. Applying the check unconditionally in `exec` keeps POSIX behavior consistent — the Windows branch is already guarded because it funnels through `spawn` — and closes the gap where a helper reference defeats the syntactic `firstPlanRefusal`. Reuse the same located message that `spawn` raises, naming the offending program.
Please fix this vulnerability. If you propose a fix, make it concise and minimal.React 👍 / 👎 to tune Strix for this repo. A repo collaborator (or the PR author) can resolve this thread to dismiss the finding.
b63174e to
145fede
Compare
7237dbc to
29f6dca
Compare
…ce hit the 0x0 pty (repl-multiline's cure, applied to the general instrument)
… EPIPE on the candidate pipe is not a cancel
29f6dca to
c30f0dc
Compare
No description provided.