Skip to content

fix(internal): restrict isAbsoluteURL scheme regex to http(s)#1888

Open
ibondarenko1 wants to merge 1 commit into
openai:masterfrom
ibondarenko1:hardening/isabsoluteurl-restrict-http-schemes
Open

fix(internal): restrict isAbsoluteURL scheme regex to http(s)#1888
ibondarenko1 wants to merge 1 commit into
openai:masterfrom
ibondarenko1:hardening/isabsoluteurl-restrict-http-schemes

Conversation

@ibondarenko1
Copy link
Copy Markdown

Problem

isAbsoluteURL at src/internal/utils/values.ts:6-10 uses /^[a-z][a-z0-9+.-]*:/i. The regex follows the WHATWG URL spec definition of "URI scheme string" and matches any RFC 3986 scheme. When an absolute-URL path reaches buildURL, the path is used as the complete URL via new URL(path) and baseURL is bypassed.

The SDK's typed resource methods (chat, completions, embeddings, etc.) all use hardcoded relative paths. The only legitimate consumer use of absolute-URL paths is via the raw client.get / client.post methods, and those should only construct HTTP or HTTPS requests.

Schemes accepted by the current regex that have no legitimate use here include file:, gopher:, ftp:, data:, javascript:.

Change

One regex narrow in src/internal/utils/values.ts:6-10. The new pattern accepts ^https?: only. A comment explains the SDK-side reasoning so a future contributor does not loosen the regex back to the spec form.

Impact

  • client.get("file:///etc/passwd"), client.get("gopher://internal/..."), client.get("data:text/html,..."), client.get("javascript:...") are now treated as relative paths rather than absolute, so buildURL rejects them via the standard new URL(baseURL + path) parse failure.
  • Standard http:// and https:// absolute paths continue to work.

Backwards compatibility

  • Public API unchanged.
  • Consumers passing http:// or https:// absolute paths to raw client.get / client.post: no behavior change.
  • Consumers passing non-HTTP schemes to raw client.get: previously bypassed baseURL; now treated as a relative path. This was not a documented use case and there are no resource methods that generate such schemes, so no internal SDK call site is affected.

Tests

  • yarn prettier --check src/internal/utils/values.ts: clean.
  • yarn eslint src/internal/utils/values.ts: clean.
  • yarn jest tests/internal tests/path.test.ts tests/index.test.ts: 212 pass.

Full yarn test requires the Stainless mock server (steady on port 4010) which is not available on the contributor side. The change is type-neutral and narrows the matching set; tests that previously passed with the broader regex still pass with the narrower one as long as they do not depend on a non-HTTP scheme.

Why this is a hardening contribution

I was reading the SDK's request pipeline and noticed the regex breadth. The SDK has no documented call site that constructs non-HTTP schemes, so the regex can be narrowed without changing intended behavior.

The SDK typed resource methods use hardcoded relative paths, so the only
schemes isAbsoluteURL needs to recognize as absolute are http and https.
The previous regex matched any RFC 3986 scheme (file:, gopher:, ftp:, data:,
javascript:), which could bypass baseURL when an absolute-URL path is passed
to client.get / client.post.
@ibondarenko1 ibondarenko1 requested a review from a team as a code owner May 18, 2026 07:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants