@@ -13,6 +13,26 @@ class BaseRequest
1313
1414 protected
1515
16+ # Resolves and validates filepath to prevent path traversal (e.g. ../../etc/passwd).
17+ # Returns a canonical path only if the file is under the current directory and is a regular file.
18+ def self . __safe_file_path__ ( filepath )
19+ raise ArgumentError , 'File path is required' if filepath . nil? || filepath . to_s . empty?
20+ expanded = File . expand_path ( filepath )
21+ base = File . realpath ( Dir . pwd )
22+ base_with_sep = base + File ::SEPARATOR
23+ unless expanded == base || expanded . start_with? ( base_with_sep )
24+ raise ArgumentError , 'File path must be under the current directory'
25+ end
26+ canonical = File . realpath ( expanded )
27+ unless canonical == base || canonical . start_with? ( base_with_sep )
28+ raise ArgumentError , 'File path must be under the current directory'
29+ end
30+ unless File . file? ( canonical )
31+ raise ArgumentError , 'File path must point to a regular file'
32+ end
33+ canonical
34+ end
35+
1636 def self . _get ( root , path , params , content_type = 'application/json' )
1737
1838 # puts path
@@ -36,7 +56,7 @@ def self._post(root, path, params, content_type='application/json', filepath=nil
3656 response = nil
3757
3858 if filepath or content_type == 'multipart/form-data'
39- params [ :file ] = File . new ( filepath , 'rb' )
59+ params [ :file ] = File . new ( self . class . __safe_file_path__ ( filepath ) , 'rb' )
4060 params [ :multipart ] = true
4161 response = RestClient . post ( url , params )
4262
0 commit comments