@@ -206,33 +206,44 @@ def _extract_and_validate_wildcards(
206206 Raises:
207207 ValueError: If a wildcard within a structurally valid value violates path traversal rules.
208208 """
209+ err = ValueError (
210+ f"Invalid value { val } for { property_name or 'positional variable' } ."
211+ )
212+
213+ # Single-segment templates (None or "*") cannot match exactly "." or ".."
214+ # and cannot have multi-segment paths resolving to 0 segments.
209215 if template_str is None or template_str == "*" :
210- if val in ("." , ".." ):
211- name_str = property_name if property_name else "positional variable"
212- raise ValueError ("Invalid value {} for {}." .format (val , name_str ))
216+ if val in ("." , ".." ) or (val and not _validate_multi_segment_value (val )):
217+ raise err
213218 return
214219
220+ # Multi-segment templates ("**") must represent at least one valid, non-escaped segment.
215221 if template_str == "**" :
216222 if not _validate_multi_segment_value (val ):
217- name_str = property_name if property_name else "positional variable"
218- raise ValueError ("Invalid value {} for {}." .format (val , name_str ))
223+ raise err
219224 return
220225
221- # Sub-template case: use cached capture pattern and regex match
226+ # Compile the sub-template into a regex capture pattern
227+ # to isolate and validate individual wildcard values.
222228 pattern , wildcard_types = _build_capture_pattern (template_str )
223229
224230 m = pattern .fullmatch (val )
225231 if m is not None :
232+ # Validate each wildcard value within its matched boundaries,
233+ # preventing traversals from escaping their structural positions.
226234 for i , wildcard_type in enumerate (wildcard_types ):
227235 captured_val = m .group (i + 1 )
228236 if wildcard_type == "*" :
229237 if captured_val in ("." , ".." ):
230- name_str = property_name if property_name else "positional variable"
231- raise ValueError ("Invalid value {} for {}." .format (val , name_str ))
238+ raise err
232239 else :
233240 if not _validate_multi_segment_value (captured_val ):
234- name_str = property_name if property_name else "positional variable"
235- raise ValueError ("Invalid value {} for {}." .format (val , name_str ))
241+ raise err
242+ else :
243+ # For values that don't match the pattern, ensure the value doesn't
244+ # resolve to 0 segments (e.g. "projects/..").
245+ if val and not _validate_multi_segment_value (val ):
246+ raise err
236247
237248
238249def _expand_variable_match (positional_vars , named_vars , match ):
0 commit comments