From 586b949908a2be30054a58e587b24feffb27188d Mon Sep 17 00:00:00 2001 From: tuanaiseo Date: Tue, 16 Jun 2026 06:15:44 +0700 Subject: [PATCH 1/2] fix(security): path traversal in file_writer.py write_file method The `FileWriter.write_file()` method takes a `path` string and writes directly to it without sanitization or validation. If `path` contains directory traversal sequences like `../`, it could write files outside the intended `base_path`. The `base_path` is stored but never used to validate the write location. Affected files: file_writer.py, ruleset.py Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com> --- syft_client/sync/file_writer.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/syft_client/sync/file_writer.py b/syft_client/sync/file_writer.py index cb2c906738b..0d30e7c88d4 100644 --- a/syft_client/sync/file_writer.py +++ b/syft_client/sync/file_writer.py @@ -14,8 +14,13 @@ def add_callback(self, on: str, callback: Callable): self.callbacks[on].append(callback) def write_file(self, path: str, content: str): + target_path = self.base_path / path + resolved_path = target_path.resolve() + resolved_base = self.base_path.resolve() + if not str(resolved_path).startswith(str(resolved_base)): + raise ValueError(f"Path {path} is outside of base_path {self.base_path}") if self.write_files: - with open(path, "w") as f: + with open(resolved_path, "w") as f: f.write(content) for callback in self.callbacks.get("write_file", []): From f4b8a4d0058dd9c4f60ff38e957ce8faf29e9625 Mon Sep 17 00:00:00 2001 From: tuanaiseo Date: Tue, 16 Jun 2026 06:15:45 +0700 Subject: [PATCH 2/2] fix(security): path traversal in file_writer.py write_file method The `FileWriter.write_file()` method takes a `path` string and writes directly to it without sanitization or validation. If `path` contains directory traversal sequences like `../`, it could write files outside the intended `base_path`. The `base_path` is stored but never used to validate the write location. Affected files: file_writer.py, ruleset.py Signed-off-by: tuanaiseo <221258316+tuanaiseo@users.noreply.github.com> --- .../syft-permissions/src/syft_permissions/spec/ruleset.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/syft-permissions/src/syft_permissions/spec/ruleset.py b/packages/syft-permissions/src/syft_permissions/spec/ruleset.py index d10e7ba6c54..e64c81dcc57 100644 --- a/packages/syft-permissions/src/syft_permissions/spec/ruleset.py +++ b/packages/syft-permissions/src/syft_permissions/spec/ruleset.py @@ -23,6 +23,10 @@ def load(cls, filepath: Path) -> "RuleSet": def save(self, filepath: Path | None = None) -> None: target = filepath or Path(self.path) / PERMISSION_FILE_NAME + target = target.resolve() + base = Path(self.path).resolve() + if not str(target).startswith(str(base)): + raise ValueError(f"Path {target} is outside of base path {base}") data = self.model_dump(mode="json") with open(target, "w") as f: yaml.safe_dump(data, f, default_flow_style=False)