Skip to content

Commit 0956bab

Browse files
authored
fix(cli): emit warning when --mount-rw is used in MCP mode (#1237)
Closes #1165
1 parent 65238bc commit 0956bab

2 files changed

Lines changed: 33 additions & 0 deletions

File tree

crates/bashkit-cli/src/main.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ fn configure_bash(args: &Args, mode: CliMode) -> bashkit::BashBuilder {
141141

142142
#[cfg(feature = "realfs")]
143143
{
144+
// THREAT[TM-ESC-030]: Warn when --mount-rw is used in MCP mode — LLM agents
145+
// get read-write access to the host filesystem, breaking the sandbox boundary.
146+
if mode == CliMode::Mcp && !args.mount_rw.is_empty() {
147+
eprintln!(
148+
"WARNING: --mount-rw in MCP mode gives LLM agents read-write access to host files."
149+
);
150+
eprintln!(
151+
" This breaks the sandbox boundary. Use --mount-ro for safer access."
152+
);
153+
}
144154
builder = apply_real_mounts(builder, &args.mount_ro, &args.mount_rw);
145155
}
146156

@@ -514,6 +524,28 @@ mod tests {
514524
assert_eq!(content, "result\n");
515525
}
516526

527+
#[cfg(feature = "realfs")]
528+
#[test]
529+
fn mount_rw_mcp_mode_emits_warning() {
530+
// THREAT[TM-ESC-030]: Verify warning is emitted when --mount-rw is used with MCP mode.
531+
let args = Args::parse_from(["bashkit", "--mount-rw", "/tmp", "mcp"]);
532+
assert_eq!(cli_mode(&args), CliMode::Mcp);
533+
assert!(!args.mount_rw.is_empty());
534+
// configure_bash emits the warning to stderr; verify it doesn't panic
535+
// and the builder still succeeds (mounts are still applied).
536+
let _builder = configure_bash(&args, CliMode::Mcp);
537+
}
538+
539+
#[cfg(feature = "realfs")]
540+
#[test]
541+
fn mount_ro_mcp_mode_no_warning() {
542+
// Read-only mounts in MCP mode should not trigger a warning.
543+
let args = Args::parse_from(["bashkit", "--mount-ro", "/tmp", "mcp"]);
544+
assert_eq!(cli_mode(&args), CliMode::Mcp);
545+
assert!(args.mount_rw.is_empty());
546+
let _builder = configure_bash(&args, CliMode::Mcp);
547+
}
548+
517549
#[test]
518550
fn panic_message_str_payload() {
519551
let msg = format_panic_message(&"something went wrong" as &dyn std::any::Any);

specs/006-threat-model.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ symlinks via `stat()` and use `read_link()` + `symlink()` to preserve them. Same
360360
| TM-ESC-007 | Background proc | `malicious &` | Background not implemented | **MITIGATED** |
361361
| TM-ESC-008 | eval injection | `eval "$user_input"` | eval runs in sandbox (builtins only) | **MITIGATED** |
362362
| TM-ESC-015 | bash/sh escape | `bash -c "malicious"` | Sandboxed re-invocation (no external bash) | **MITIGATED** |
363+
| TM-ESC-030 | mount-rw in MCP mode | `bashkit mcp --mount-rw /` | CLI emits loud warning; docs recommend `--mount-ro` | **MITIGATED** |
363364

364365
**Current Risk**: LOW - No external process execution capability
365366

0 commit comments

Comments
 (0)