@ -157,17 +157,20 @@ def sanitize_filename(filename: str) -> str:
# Remove control characters and non-printable characters
# Remove control characters and non-printable characters
filename = re . sub ( r ' [ \ x00- \ x1f \ x7f] ' , ' ' , filename )
filename = re . sub ( r ' [ \ x00- \ x1f \ x7f] ' , ' ' , filename )
# remove potential $( ) and ${ }
filename = re . sub ( r ' \ $[ \ ( \ { ].*?[ \ ) \ }] ' , ' ' , filename )
# remove any remaining $( or ${
filename = filename . replace ( ' $( ' , ' ' ) . replace ( ' $ { ' , ' ' )
# Allow alphanumeric, underscore, hyphen, space, and dots
# Allow alphanumeric, underscore, hyphen, space, and dots
# Remove other potentially dangerous characters.
# Remove other potentially dangerous characters.
filename = re . sub ( r ' [^a-zA-Z0-9_ \ - \ . \ ] ' , ' _ ' , filename )
filename = re . sub ( r ' [^a-zA-Z0-9_ \ - \ . \ ] ' , ' ', filename )
# Remove consecutive dots to prevent directory traversal attempts like '..'
# Remove consecutive dots to prevent directory traversal attempts like '..'
filename = re . sub ( r ' \ . { 2,} ' , ' . ' , filename )
filename = re . sub ( r ' \ . { 2,} ' , ' . ' , filename )
# remove potential $(
filename = re . sub ( r ' \ $ \ ([ \ s \ S]*? \ ) ' , ' ' , filename )
# Ensure filename is not practically empty after sanitization
# Ensure filename is not practically empty after sanitization
if not filename . strip ( ) or filename . strip ( ) . replace ( ' . ' , ' ' ) == ' ' :
if not filename . strip ( ) or filename . strip ( ) . replace ( ' . ' , ' ' ) == ' ' :
raise ValueError ( " Filename invalid after sanitization " )
raise ValueError ( " Filename invalid after sanitization " )