From f0dc094cd6d2a3eaea078d5ea4c2f285b7df578f Mon Sep 17 00:00:00 2001 From: 5ymb01 <5ymb01ixm@gmail.com> Date: Fri, 20 Mar 2026 10:04:49 -0400 Subject: [PATCH] fix(security): use Path.relative_to() for path confinement (#284) * fix(security): use Path.relative_to() for path confinement check Replace str.startswith() path check with Path.relative_to() in the plugin file viewer endpoint. startswith() can be bypassed when a directory name is a prefix of another (e.g., /plugins/foo vs /plugins/foobar). relative_to() correctly validates containment. Co-Authored-By: 5ymb01 Co-Authored-By: Claude Opus 4.6 * chore: trigger CodeRabbit review --------- Co-authored-by: 5ymb01 <5ymb01@users.noreply.github.com> Co-authored-by: 5ymb01 Co-authored-by: Claude Opus 4.6 --- web_interface/blueprints/api_v3.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web_interface/blueprints/api_v3.py b/web_interface/blueprints/api_v3.py index fec8eedf..9b8656a6 100644 --- a/web_interface/blueprints/api_v3.py +++ b/web_interface/blueprints/api_v3.py @@ -6286,7 +6286,9 @@ def serve_plugin_static(plugin_id, file_path): requested_file = (plugin_dir / file_path).resolve() # Security check: ensure file is within plugin directory - if not str(requested_file).startswith(str(plugin_dir)): + try: + requested_file.relative_to(plugin_dir) + except ValueError: return jsonify({'status': 'error', 'message': 'Invalid file path'}), 403 # Check if file exists