You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
CommandResolver::resolve ran embedder host code on attacker-controlled unresolved names without a panic boundary, allowing resolver panics to unwind out of Bash::exec and break the interpreter availability guarantees (TM-INT-001).
The goal is to ensure resolver failures behave like builtin failures: sanitized shell errors with non-zero exit codes instead of unwinding the process.
Description
Wrap the resolver call in std::panic::catch_unwind(AssertUnwindSafe(...)) in crates/bashkit/src/interpreter/mod.rs and return a sanitized ExecResult::err(..., 1) on panic.
Preserve the existing dispatch: a successfully returned Arc<dyn Builtin> still runs via execute_builtin_arc so before_tool and the builtin catch_unwind boundary remain in effect.
Add an integration regression test resolver_panic_becomes_a_sanitized_shell_error in crates/bashkit/tests/integration/command_resolver_tests.rs that asserts a resolver panic becomes a sanitized shell error and does not leak panic payloads.
Update API/docs and canonical knowledge (crates/bashkit/src/builtins/mod.rs, knowledge/foundations/builtins.md, knowledge/security/threat-model.md, crates/bashkit/docs/threat-model.md) to document that resolver resolution is panic-contained (TM-INT-010).
Testing
Ran the new integration test cargo test -p bashkit --test integration command_resolver_tests::resolver_panic_becomes_a_sanitized_shell_error -- --exact, which passed.
Ran the resolver integration subset cargo test -p bashkit --test integration command_resolver_tests::, and all resolver-related tests passed (12 passed, 0 failed).
Ran formatting and policy checks with cargo fmt --all and just check-okf, both of which exited successfully.
Ran cargo clippy -p bashkit --tests -- -D warnings, which completed without warnings.
Reviewed and rebased onto main. Good fix, and the only one in this batch so far with a test that genuinely fails without the change:
test command_resolver_tests::resolver_panic_becomes_a_sanitized_shell_error ... FAILED
(with main's interpreter/mod.rs, PR's tests)
test command_resolver_tests::resolver_panic_becomes_a_sanitized_shell_error ... ok
(with the PR)
CommandResolver::resolve is embedder code reached with an attacker-controlled name, and it was the one host callback on that path not already inside a catch_unwind. Containing it and returning the sanitized resolver failed unexpectedly matches how TM-INT-002 already handles builtin panics, and the assertion that the panic payload is not in stderr is the right thing to pin.
Renumbered TM-INT-010 → TM-INT-011.#2331 (now merged) also claimed TM-INT-010; the rebase surfaced this as a direct conflict in both threat-model files. Resolved by keeping both rows and giving this one 011, updating the THREAT[...] marker in interpreter/mod.rs and the "Current Risk" prose to match.
Also merged the knowledge/foundations/builtins.md conflict by hand — main had reworded that paragraph's punctuation while this PR extended its content, so both changes are preserved rather than one overwriting the other.
Full command_resolver suite (15 tests) and the threat-model doc tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
CommandResolver::resolveran embedder host code on attacker-controlled unresolved names without a panic boundary, allowing resolver panics to unwind out ofBash::execand break the interpreter availability guarantees (TM-INT-001).Description
std::panic::catch_unwind(AssertUnwindSafe(...))incrates/bashkit/src/interpreter/mod.rsand return a sanitizedExecResult::err(..., 1)on panic.Arc<dyn Builtin>still runs viaexecute_builtin_arcsobefore_tooland the builtincatch_unwindboundary remain in effect.resolver_panic_becomes_a_sanitized_shell_errorincrates/bashkit/tests/integration/command_resolver_tests.rsthat asserts a resolver panic becomes a sanitized shell error and does not leak panic payloads.crates/bashkit/src/builtins/mod.rs,knowledge/foundations/builtins.md,knowledge/security/threat-model.md,crates/bashkit/docs/threat-model.md) to document that resolver resolution is panic-contained (TM-INT-010).Testing
cargo test -p bashkit --test integration command_resolver_tests::resolver_panic_becomes_a_sanitized_shell_error -- --exact, which passed.cargo test -p bashkit --test integration command_resolver_tests::, and all resolver-related tests passed (12 passed, 0 failed).cargo fmt --allandjust check-okf, both of which exited successfully.cargo clippy -p bashkit --tests -- -D warnings, which completed without warnings.Codex Task