Skip to content

fix: reject unsafe URL path segments in the 4.x SDK - #726

Closed
gjtorikian wants to merge 1 commit into
4.xfrom
workgraph/workos-python-6md-dbe10bae
Closed

gjtorikian wants to merge 1 commit into
4.xfrom
workgraph/workos-python-6md-dbe10bae

Conversation

@gjtorikian

Copy link
Copy Markdown
Contributor

Description

  • Prevent empty or dot-only identifiers from retargeting SDK requests after URL normalization; quoting alone does not escape . or ...
  • Apply one shared segment encoder to all 31 path-template interpolations and the URL builder used by four MFA endpoints, without changing query/body values or unrelated string formatting.
  • Add 24 regression cases covering segment validation/encoding, rejection before any HTTP call at destructive endpoints, and the encoded get_user('a/b') request URL.

This is the approved VULN-1272 adaptation for the requests-based 4.x branch. The finding's src/workos/_base_client.py and pipes/groups/authorization resource layout is not present on this branch.

Compatibility

Path identifiers equal to '', '.', or '..' now raise ValueError before any HTTP request. Characters /, ?, #, and % are percent-encoded rather than interpreted as URL structure. Callers must pass raw, not pre-encoded identifiers: a/b becomes a%2Fb, and %2e%2e becomes %252e%252e.

Validation

  • python -m pytest: 224 passed (verified baseline: 200; 24 new cases), with existing deprecation warnings.
  • black --check .: clean.
  • flake8 . --count --select=E9,F7,F82 --show-source --statistics: zero findings.
  • Pre-fix archive with new regression tests: all 10 endpoint cases fail; helper tests fail to collect because the helper is absent. All pass on the fixed tree.
  • Scope audit: exactly the 10 approved files; all 31 path-template sinks use the encoder and all four MFA sinks use the shared builder. No live WorkOS API requests were used for verification.

Documentation

No WorkOS API reference or endpoint contract changes. The intentional SDK input-handling behavior change is documented above and in the helper docstring for release-note visibility.

Dot segments can be normalized into a different endpoint, making an
identifier capable of retargeting a destructive request. URL quoting
alone cannot prevent this because '.' and '..' remain unescaped.

Empty identifiers and bare dot segments now raise ValueError before any
HTTP request. Slashes, question marks, hashes, and percent signs in path
identifiers are encoded rather than interpreted as URL structure.
Callers must pass raw identifiers; pre-encoded values are double-encoded.

This applies the VULN-1272 remediation to the requests-based 4.x SDK.
@gjtorikian
gjtorikian requested a review from a team as a code owner September 11, 2026 16:06
@gjtorikian
gjtorikian requested review from nicknisi and removed request for a team September 11, 2026 16:06
@greptile-apps

greptile-apps Bot commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

The PR appears safe to merge; dynamic path identifiers are consistently validated and encoded, with focused regression coverage.

Summary

  • Adds encode_path_segment and applies it across all dynamic request-path interpolations.
  • Updates the shared parameterized URL builder used by MFA endpoints.
  • Adds regression coverage for rejected segments, reserved-character encoding, and validation before destructive HTTP requests.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Raw SDK identifier] --> B[encode_path_segment]
  B --> C{Empty, dot, or dot-dot?}
  C -->|Yes| D[Raise ValueError before HTTP request]
  C -->|No| E[Percent-encode as one path segment]
  E --> F[Insert into endpoint template]
  F --> G[RequestHelper sends request]
Loading

Reviews (1) · Last reviewed commit: "fix: reject unsafe URL path segments"

@gjtorikian

Copy link
Copy Markdown
Contributor Author

Closing: this PR targets 4.x, but VULN-1272 is about _encode_path in src/workos/_base_client.py on main, which this branch does not have. The fix for main is #728. The 4.x-specific hardening here can be reopened separately if we still want it on that line.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant