Skip to content

Commit 7c8b94e

Browse files
committed
added extra check for valdidity
1 parent 33741f8 commit 7c8b94e

2 files changed

Lines changed: 34 additions & 10 deletions

File tree

packages/google-api-core/google/api_core/path_template.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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

238249
def _expand_variable_match(positional_vars, named_vars, match):

packages/google-api-core/tests/unit/test_path_template.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,19 @@ def helper_test_transcode(http_options_list, expected_result_list):
717717
{"parent": "projects/my-project/locations/."},
718718
"Invalid value projects/my-project/locations/\\. for parent\\.",
719719
],
720+
# Non-matching values with path traversal (bypass prevention)
721+
[
722+
"/v2/{parent=projects/*/locations/*}/content:inspect",
723+
[],
724+
{"parent": "projects/.."},
725+
"Invalid value projects/\\.\\. for parent\\.",
726+
],
727+
[
728+
"/v1/{name}",
729+
[],
730+
{"name": "projects/.."},
731+
"Invalid value projects/\\.\\. for name\\.",
732+
],
720733
],
721734
)
722735
def test_path_traversal_dots_validation_star(tmpl, args, kwargs, expected_err_match):

0 commit comments

Comments
 (0)