Skip to content

Commit 0d4cc70

Browse files
Reject invisible separator characters in baseURL
Co-authored-by: Eric Allam <eric@trigger.dev>
1 parent 4432ba4 commit 0d4cc70

File tree

6 files changed

+27
-2
lines changed

6 files changed

+27
-2
lines changed

.changeset/curly-radios-visit.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ Add a new `@trigger.dev/ai` package with:
1010
- reconnect-aware stream handling on top of Trigger.dev Realtime Streams v2
1111
- strict `baseURL` normalization/validation (trimming, path-safe slash handling, absolute `http(s)` URLs only, no query/hash/credentials)
1212
- rejection of internal whitespace characters in normalized `baseURL` values
13+
- rejection of internal invisible separator characters (e.g. zero-width spaces) in normalized `baseURL` values
1314
- deterministic baseURL validation error ordering for multi-issue inputs (internal whitespace → protocol → query/hash → credentials)
1415
- explicit default `baseURL` behavior (`https://api.trigger.dev`) and case-insensitive `HTTP(S)` protocol acceptance

docs/tasks/streams.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,7 @@ Examples:
676676
-`https://api.trigger.dev/\ninternal`
677677
-`https://api.trigger.dev/\tinternal`
678678
-`https://api.trigger.dev/\rinternal`
679+
-`https://api.trigger.dev/\u200Binternal`
679680

680681
Validation errors use these exact messages:
681682

packages/ai/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
- Added explicit validation that `baseURL` uses `http` or `https`.
2727
- Added explicit validation that `baseURL` excludes query parameters and hash fragments.
2828
- Added explicit validation that `baseURL` excludes username/password credentials.
29-
- Added explicit validation that `baseURL` excludes internal whitespace characters.
29+
- Added explicit validation that `baseURL` excludes internal whitespace/invisible separator characters.
3030
- Documented that `HTTP://` and `HTTPS://` are accepted (case-insensitive protocol matching).
3131
- Added deterministic validation ordering for multi-issue baseURL values
3232
(internal whitespace → protocol → query/hash → credentials).

packages/ai/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ Examples:
183183
-`https://api.trigger.dev/\ninternal` (internal whitespace characters)
184184
-`https://api.trigger.dev/\tinternal` (internal tab characters)
185185
-`https://api.trigger.dev/\rinternal` (internal carriage-return characters)
186+
-`https://api.trigger.dev/\u200Binternal` (internal zero-width-space characters)
186187

187188
Validation errors use these exact messages:
188189

packages/ai/src/chatTransport.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,17 @@ describe("TriggerChatTransport", function () {
753753
}).toThrowError("baseURL must not contain internal whitespace characters");
754754
});
755755

756+
it("throws when baseURL contains internal zero-width-space characters", function () {
757+
expect(function () {
758+
new TriggerChatTransport({
759+
task: "chat-task",
760+
accessToken: "pk_trigger",
761+
baseURL: "https://api.trigger.dev/\u200Binternal",
762+
stream: "chat-stream",
763+
});
764+
}).toThrowError("baseURL must not contain internal whitespace characters");
765+
});
766+
756767
it("throws when baseURL is a relative path", function () {
757768
expect(function () {
758769
new TriggerChatTransport({
@@ -3371,6 +3382,17 @@ describe("TriggerChatTransport", function () {
33713382
}).toThrowError("baseURL must not contain internal whitespace characters");
33723383
});
33733384

3385+
it("throws from factory when baseURL contains internal zero-width-space characters", function () {
3386+
expect(function () {
3387+
createTriggerChatTransport({
3388+
task: "chat-task",
3389+
accessToken: "pk_trigger",
3390+
baseURL: "https://api.trigger.dev/\u200Binternal",
3391+
stream: "chat-stream",
3392+
});
3393+
}).toThrowError("baseURL must not contain internal whitespace characters");
3394+
});
3395+
33743396
it("throws from factory when baseURL protocol is not http or https", function () {
33753397
expect(function () {
33763398
createTriggerChatTransport({

packages/ai/src/chatTransport.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ const BASE_URL_VALIDATION_ERRORS = {
457457
credentials: "baseURL must not include username or password credentials",
458458
} as const;
459459

460-
const INTERNAL_WHITESPACE_REGEX = /\s/;
460+
const INTERNAL_WHITESPACE_REGEX = /[\s\u200B\u200C\u200D\u2060\uFEFF]/u;
461461

462462
function resolvePayloadMapper<
463463
UI_MESSAGE extends UIMessage,

0 commit comments

Comments
 (0)