@@ -196,6 +196,22 @@ public static bool ContainsPath(string? fullPath, string? path, bool excludeSame
196196 }
197197 }
198198
199+ /* Test that the given `fullPath` exists within the given `path` directory.
200+ * If it does not, throw an exception to terminate the request.
201+ */
202+ public static void ContainsPathValidationThrowing ( string ? fullPath , string ? path )
203+ {
204+ fullPath = Path . GetFullPath ( fullPath ) ;
205+ path = Path . GetFullPath ( path ) ;
206+
207+ fullPath = AddBackslashIfNotPresent ( fullPath ) ;
208+ path = AddBackslashIfNotPresent ( path ) ;
209+
210+ if ( ! fullPath ! . StartsWith ( path , StringComparison . OrdinalIgnoreCase ) ) {
211+ throw new Exception ( "Attempting path traversal" ) ;
212+ }
213+ }
214+
199215 static void Main ( string [ ] args )
200216 {
201217 string zipFileName ;
@@ -231,5 +247,19 @@ static void fp_throw(ZipArchive archive, string root){
231247 entry . ExtractToFile ( destinationOnDisk , true ) ;
232248 }
233249 }
250+
251+ /**
252+ * Negative - dangerous path terminates early due to exception thrown by guarded condition in descendent call.
253+ */
254+ static void fp_throw_nested_exception ( ZipArchive archive , string root ) {
255+ foreach ( var entry in archive . Entries ) {
256+ string destinationOnDisk = Path . GetFullPath ( Path . Combine ( root , entry . FullName ) ) ;
257+ string fullRoot = Path . GetFullPath ( root + Path . DirectorySeparatorChar ) ;
258+ ContainsPathValidationThrowing ( destinationOnDisk , fullRoot ) ;
259+ // NEGATIVE, above exception short circuits by exception on invalid input by path traversal.
260+ entry . ExtractToFile ( destinationOnDisk , true ) ;
261+ }
262+ }
263+
234264 }
235265}
0 commit comments