@@ -127,10 +127,10 @@ private static bool IsValidScheme(ReadOnlySpan<char> scheme)
127127 }
128128
129129 /// <summary>
130- /// Validates the path for security issues such as path traversal attacks .
130+ /// Validates the path for security issues: path traversal and absolute paths .
131131 /// </summary>
132132 /// <param name="path">The path to validate.</param>
133- /// <exception cref="ArgumentException">Thrown when path traversal is detected .</exception>
133+ /// <exception cref="ArgumentException">Thrown when the path is absolute or contains traversal sequences .</exception>
134134 private static void ValidatePathSecurity ( string path )
135135 {
136136 if ( path . Contains ( ".." ) )
@@ -139,25 +139,37 @@ private static void ValidatePathSecurity(string path)
139139 $ "Invalid path (path traversal detected): { path } ",
140140 nameof ( path ) ) ;
141141 }
142+
143+ if ( Path . IsPathRooted ( path ) )
144+ {
145+ throw new ArgumentException (
146+ $ "Absolute paths are not allowed for security reasons: { path } . Use relative paths resolved against BasePath.",
147+ nameof ( path ) ) ;
148+ }
142149 }
143150
144151 /// <summary>
145- /// Resolves a relative or absolute path to a full file system path .
152+ /// Resolves a relative path against BasePath and validates the result stays within bounds .
146153 /// </summary>
147- /// <param name="path">The path to resolve.</param>
154+ /// <param name="path">The relative path to resolve.</param>
148155 /// <returns>The fully resolved absolute path.</returns>
156+ /// <exception cref="ArgumentException">Thrown when the resolved path escapes the base directory.</exception>
149157 private string ResolvePath ( string path )
150158 {
151- if ( Path . IsPathRooted ( path ) )
152- {
153- return Path . GetFullPath ( path ) ;
154- }
159+ var basePath = ! string . IsNullOrEmpty ( _options . BasePath )
160+ ? Path . GetFullPath ( _options . BasePath )
161+ : Path . GetFullPath ( "." ) ;
155162
156- if ( ! string . IsNullOrEmpty ( _options . BasePath ) )
163+ var fullPath = Path . GetFullPath ( Path . Combine ( basePath , path ) ) ;
164+
165+ // Ensure the resolved path is still within the base directory
166+ if ( ! fullPath . StartsWith ( basePath , StringComparison . Ordinal ) )
157167 {
158- return Path . GetFullPath ( Path . Combine ( _options . BasePath , path ) ) ;
168+ throw new ArgumentException (
169+ $ "Path '{ path } ' resolves outside the base directory.",
170+ nameof ( path ) ) ;
159171 }
160172
161- return Path . GetFullPath ( path ) ;
173+ return fullPath ;
162174 }
163175}
0 commit comments