@@ -369,7 +369,11 @@ private static async Task IndexArchiveAsync(
369369 {
370370 cancellationToken . ThrowIfCancellationRequested ( ) ;
371371
372- string entryKey = archiveFileLayoutPolicy . NormalizeRelativePath ( entry . Key ?? string . Empty ) ;
372+ if ( ! TryNormalizeArchiveEntryKey ( entry , archiveFileLayoutPolicy , out string entryKey ) )
373+ {
374+ continue ;
375+ }
376+
373377 if ( IsSupportedArchiveFile ( entryKey ) )
374378 {
375379 await IndexArchiveAsync (
@@ -438,10 +442,8 @@ private static async ValueTask<Stream> OpenEntryStreamAsync(
438442
439443 IArchiveEntry entry = archive . Entries . FirstOrDefault ( candidate =>
440444 ! candidate . IsDirectory
441- && string . Equals (
442- archiveFileLayoutPolicy . NormalizeRelativePath ( candidate . Key ?? string . Empty ) ,
443- archiveFileLayoutPolicy . NormalizeRelativePath ( entryKey ) ,
444- StringComparison . Ordinal ) )
445+ && TryNormalizeArchiveEntryKey ( candidate , archiveFileLayoutPolicy , out string candidateKey )
446+ && string . Equals ( candidateKey , archiveFileLayoutPolicy . NormalizeRelativePath ( entryKey ) , StringComparison . Ordinal ) )
445447 ?? throw new FileNotFoundException ( $ "The dataset entry '{ entryKey } ' was not found in '{ archivePath } '.") ;
446448
447449 await using Stream entryStream = await entry . OpenEntryStreamAsync ( cancellationToken ) ;
@@ -458,5 +460,41 @@ private static bool IsSupportedArchiveFile(string path)
458460 || string . Equals ( extension , ".7z" , StringComparison . OrdinalIgnoreCase ) ;
459461 }
460462
463+ private static bool TryNormalizeArchiveEntryKey (
464+ IArchiveEntry entry ,
465+ IArchiveFileLayoutPolicy archiveFileLayoutPolicy ,
466+ out string entryKey )
467+ {
468+ entryKey = string . Empty ;
469+
470+ if ( string . IsNullOrWhiteSpace ( entry . Key ) )
471+ {
472+ return false ;
473+ }
474+
475+ string rawKey = entry . Key . Replace ( '\\ ' , '/' ) . Trim ( ) ;
476+ if ( rawKey . StartsWith ( '/' )
477+ || Path . IsPathFullyQualified ( rawKey )
478+ || ( rawKey . Length >= 2 && rawKey [ 1 ] == ':' ) )
479+ {
480+ return false ;
481+ }
482+
483+ string normalizedKey = archiveFileLayoutPolicy . NormalizeRelativePath ( rawKey ) ;
484+ if ( normalizedKey . Length == 0 )
485+ {
486+ return false ;
487+ }
488+
489+ string [ ] segments = normalizedKey . Split ( '/' , StringSplitOptions . RemoveEmptyEntries ) ;
490+ if ( segments . Any ( static segment => segment is "." or ".." ) )
491+ {
492+ return false ;
493+ }
494+
495+ entryKey = normalizedKey ;
496+ return true ;
497+ }
498+
461499 }
462500}
0 commit comments