@@ -351,6 +351,8 @@ public static object EvaluatePythonScript(
351351 private static bool isPythonInstalled = false ;
352352 /// <summary>
353353 /// Makes sure Python is installed on the system and its location added to the path.
354+ /// Extracts non-pip wheels directly from the embedded resource stream into site-packages,
355+ /// adds a zip-slip guard (normalize & validate paths), and uses pip only for pywin32.
354356 /// NOTE: Calling SetupPython multiple times will add the install location to the path many times,
355357 /// potentially causing the environment variable to overflow.
356358 /// </summary>
@@ -370,12 +372,14 @@ internal static async Task InstallPythonAsync()
370372
371373 Assembly wheelsAssembly = context . LoadFromAssemblyPath ( Path . Join ( Path . GetDirectoryName ( assembly . Location ) , "DSPythonNet3Wheels.dll" ) ) ;
372374
373- string sitePkgsPath = Path . Combine ( Python . Included . Installer . EmbeddedPythonHome , "Lib" , "site-packages" ) ;
374- Directory . CreateDirectory ( sitePkgsPath ) ;
375+ string sitePkgs = Path . Combine ( Python . Included . Installer . EmbeddedPythonHome , "Lib" , "site-packages" ) ;
376+ var normalizedBase = Path . GetFullPath ( sitePkgs ) + Path . DirectorySeparatorChar ;
377+
378+ Directory . CreateDirectory ( sitePkgs ) ;
375379
376380 List < string > pipWheelInstall = new List < string > ( ) ;
377381
378- // Extract noo -pip wheels directly from the resource stream
382+ // Extract non -pip wheels directly from the resource stream
379383 foreach ( var resName in wheelsAssembly . GetManifestResourceNames ( ) )
380384 {
381385 bool isWheel = resName . EndsWith ( ".whl" ) ;
@@ -400,7 +404,16 @@ internal static async Task InstallPythonAsync()
400404 {
401405 if ( string . IsNullOrEmpty ( entry . Name ) ) continue ;
402406
403- var destPath = Path . Combine ( sitePkgsPath , entry . FullName . Replace ( '/' , Path . DirectorySeparatorChar ) ) ;
407+ var relPath = entry . FullName . Replace ( '/' , Path . DirectorySeparatorChar ) ;
408+ var tentative = Path . Combine ( sitePkgs , relPath ) ;
409+ var destPath = Path . GetFullPath ( tentative ) ;
410+
411+ if ( ! destPath . StartsWith ( normalizedBase , StringComparison . OrdinalIgnoreCase ) )
412+ {
413+ dynamoLogger ? . LogWarning ( $ "[PyInit] Skipped suspicious wheel entry: { entry . FullName } ", WarningLevel . Mild ) ;
414+ continue ;
415+ }
416+
404417 var destDir = Path . GetDirectoryName ( destPath ) ;
405418 if ( ! string . IsNullOrEmpty ( destDir ) )
406419 {
0 commit comments