From 5de7ebfc952c07f376b2c25f3789742071748d5a Mon Sep 17 00:00:00 2001 From: Lucas Fernandes Nogueira Date: Fri, 9 Oct 2026 13:05:12 -0300 Subject: [PATCH] fix(fs): do not deserialize customFlags from IPC (#3634) In plugins/fs/src/lib.rs OpenOptions, custom_flags was deserializable from the `open` command arguments even though it is not in the TS types, so a webview with a read-only permission set could pass arbitrary open(2) flags such as O_TRUNC. The field is now #[serde(skip)]; Rust callers still set it through OpenOptionsExt. Rejecting write/truncate/create options of `open` under read-only sets changes permission semantics and is deferred to v3. --- .changes/fix-fs-open-custom-flags.md | 6 ++++++ plugins/fs/src/lib.rs | 12 +++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 .changes/fix-fs-open-custom-flags.md diff --git a/.changes/fix-fs-open-custom-flags.md b/.changes/fix-fs-open-custom-flags.md new file mode 100644 index 000000000..d633ce1b7 --- /dev/null +++ b/.changes/fix-fs-open-custom-flags.md @@ -0,0 +1,6 @@ +--- +fs: patch +fs-js: patch +--- + +**Security:** the `open` command no longer accepts a `customFlags` option from the webview. It was not part of the JavaScript types and let the webview pass arbitrary `open(2)` flags (e.g. `O_TRUNC`) to files it may only read. `OpenOptionsExt::custom_flags` still works from Rust. diff --git a/plugins/fs/src/lib.rs b/plugins/fs/src/lib.rs index ed7854c21..508a4ea45 100644 --- a/plugins/fs/src/lib.rs +++ b/plugins/fs/src/lib.rs @@ -83,7 +83,9 @@ pub struct OpenOptions { #[serde(default)] #[allow(unused)] mode: Option, - #[serde(default)] + // Never deserialized: the webview must not be able to pass arbitrary `open(2)` flags + // (e.g. `O_TRUNC`), it can only be set from Rust with `OpenOptionsExt::custom_flags`. + #[serde(skip)] #[allow(unused)] custom_flags: Option, } @@ -663,4 +665,12 @@ mod tests { "w" ); } + + #[test] + fn open_options_ignore_custom_flags_from_ipc() { + let options: OpenOptions = + serde_json::from_str(r#"{ "read": true, "customFlags": 512 }"#).unwrap(); + assert!(options.read); + assert_eq!(options.custom_flags, None); + } }