@@ -24,6 +24,15 @@ enum HostEnvSanitizer {
2424 " NO_COLOR " ,
2525 " FORCE_COLOR " ,
2626 ]
27+ private static let gitAllowProtocolKey = " GIT_ALLOW_PROTOCOL "
28+ private static let gitProtocolFromUserKey = " GIT_PROTOCOL_FROM_USER "
29+ private static let gitProtocolFromUserDisabledValue = " 0 "
30+ private static let gitDefaultAlwaysAllowedProtocols : Set < String > = [
31+ " git " ,
32+ " http " ,
33+ " https " ,
34+ " ssh " ,
35+ ]
2736
2837 private static func isBlocked( _ upperKey: String ) -> Bool {
2938 if self . blockedKeys. contains ( upperKey) { return true }
@@ -82,6 +91,25 @@ enum HostEnvSanitizer {
8291 Array ( Set ( values) ) . sorted ( )
8392 }
8493
94+ private static func isPermissiveGitProtocolFromUserValue( _ value: String ) -> Bool {
95+ let normalized = value. trimmingCharacters ( in: . whitespacesAndNewlines) . lowercased ( )
96+ if normalized == " true " || normalized == " yes " || normalized == " on " {
97+ return true
98+ }
99+ let isInteger = normalized. range ( of: #"^[+-]?[0-9]+$"# , options: . regularExpression) != nil
100+ let isZero = normalized. range ( of: #"^[+-]?0+$"# , options: . regularExpression) != nil
101+ return isInteger && !isZero
102+ }
103+
104+ private static func sanitizeInheritedGitAllowProtocolValue( _ value: String ) -> String {
105+ let normalized = value. trimmingCharacters ( in: . whitespacesAndNewlines)
106+ if normalized. isEmpty { return " " }
107+ let safeProtocols = normalized
108+ . split ( separator: " : " , omittingEmptySubsequences: false )
109+ . filter { self . gitDefaultAlwaysAllowedProtocols. contains ( String ( $0) ) }
110+ return safeProtocols. joined ( separator: " : " )
111+ }
112+
85113 static func inspectOverrides(
86114 overrides: [ String : String ] ? ,
87115 blockPathOverrides: Bool = true ) -> HostEnvOverrideDiagnostics
@@ -120,6 +148,22 @@ enum HostEnvSanitizer {
120148 let key = rawKey. trimmingCharacters ( in: . whitespacesAndNewlines)
121149 guard !key. isEmpty else { continue }
122150 let upper = key. uppercased ( )
151+ // Preserve inherited Git allowlists without widening malformed or unsafe entries by
152+ // deletion. Protocols outside Git's safe default set are removed instead.
153+ if upper == self . gitAllowProtocolKey {
154+ merged [ key] = self . sanitizeInheritedGitAllowProtocolValue ( value)
155+ continue
156+ }
157+ // Preserve non-permissive Git boolean values. Permissive values must become explicit
158+ // `0` because Git's unset default still permits protocols with policy `user`.
159+ if upper == self . gitProtocolFromUserKey {
160+ if !self . isPermissiveGitProtocolFromUserValue ( value) {
161+ merged [ key] = value
162+ } else {
163+ merged [ key] = self . gitProtocolFromUserDisabledValue
164+ }
165+ continue
166+ }
123167 if self . isBlockedInherited ( upper) { continue }
124168 merged [ key] = value
125169 }
0 commit comments