@@ -277,6 +277,7 @@ def _powershell_urlopen(request):
277277
278278def _powershell_urlretrieve (request ):
279279 from base64 import b64encode
280+ import json
280281 import subprocess
281282
282283 headers = request .headers
@@ -287,23 +288,27 @@ def _powershell_urlretrieve(request):
287288 if auth :
288289 headers = {** headers , "Authorization" : _basic_auth_header (* auth )}
289290
290- def _f (v ):
291- if isinstance (v , str ):
292- return "'" + v .replace ("'" , "''" ) + "'"
293- return str (v )
294-
295- ps_headers = " " .join (f"{ k !r} ={ _f (v )} ;" for k , v in headers .items ())
296-
297291 powershell = Path (os .getenv ("SystemRoot" )) / "System32/WindowsPowerShell/v1.0/powershell.exe"
298- script = fr"""$ProgressPreference = "SilentlyContinue"
299- $headers = @{{ { ps_headers } }}
300- $r = Invoke-WebRequest '{ request .url } ' -UseBasicParsing `
292+ # Security hardening: avoid PowerShell command injection by using env vars instead of interpolation
293+ script = r"""$ProgressPreference = "SilentlyContinue"
294+ $url = $env:PYMANAGER_URL
295+ $outfile = $env:PYMANAGER_OUTFILE
296+ $method = $env:PYMANAGER_METHOD
297+ $headers = ConvertFrom-Json $env:PYMANAGER_HEADERS
298+ $r = Invoke-WebRequest -Uri $url -UseBasicParsing `
301299 -Headers $headers `
302300 -UseDefaultCredentials `
303- -Method " { request . method } " `
304- -OutFile " { request . outfile } "
301+ -Method $ method `
302+ -OutFile $ outfile
305303"""
306- LOGGER .debug ("PowerShell script: %s" , script )
304+ LOGGER .debug ("PowerShell download invoked (env-based)" )
305+ env = os .environ .copy ()
306+ env .update ({
307+ "PYMANAGER_URL" : request .url ,
308+ "PYMANAGER_OUTFILE" : str (request .outfile ),
309+ "PYMANAGER_METHOD" : request .method ,
310+ "PYMANAGER_HEADERS" : json .dumps (headers ),
311+ })
307312 with subprocess .Popen (
308313 [powershell ,
309314 "-ExecutionPolicy" , "Bypass" ,
@@ -312,6 +317,7 @@ def _f(v):
312317 "-EncodedCommand" , b64encode (script .encode ("utf-16-le" ))
313318 ],
314319 cwd = request .outfile .parent ,
320+ env = env ,
315321 creationflags = subprocess .CREATE_NO_WINDOW ,
316322 stdout = subprocess .PIPE ,
317323 stderr = subprocess .STDOUT ,
0 commit comments