Reject mongolian-vowel-separator baseURL invisible whitespace

Co-authored-by: Eric Allam <eric@trigger.dev>
This commit is contained in:
Cursor Agent
2026-02-15 07:05:29 +00:00
parent d1e9220f71
commit 28becff377
6 changed files with 53 additions and 1 deletions
+2
View File
@@ -16,5 +16,7 @@ Add a new `@trigger.dev/ai` package with:
values that normalize to empty after trimming
- expanded unicode whitespace handling coverage to include figure space (`\u2007`) and medium
mathematical space (`\u205F`) for both wrapper trimming and internal-whitespace rejection
- expanded invisible-separator rejection coverage to include mongolian vowel separator (`\u180E`)
in both wrapper and internal `baseURL` positions
- deterministic baseURL validation error ordering for multi-issue inputs (internal whitespace → protocol → query/hash → credentials)
- explicit default `baseURL` behavior (`https://api.trigger.dev`) and case-insensitive `HTTP(S)` protocol acceptance
+2
View File
@@ -679,6 +679,7 @@ Examples:
- ❌ `\u200Bhttps://api.trigger.dev/custom-prefix/\u200B` (zero-width-space wrappers are rejected)
- ❌ `\u200Chttps://api.trigger.dev/custom-prefix/\u200C` (zero-width-non-joiner wrappers are rejected)
- ❌ `\u200Dhttps://api.trigger.dev/custom-prefix/\u200D` (zero-width-joiner wrappers are rejected)
- ❌ `\u180Ehttps://api.trigger.dev/custom-prefix/\u180E` (mongolian-vowel-separator wrappers are rejected)
- ❌ `https://api.trigger.dev?foo=bar`
- ❌ `https://api.trigger.dev#fragment`
- ❌ `https://user:pass@api.trigger.dev`
@@ -705,6 +706,7 @@ Examples:
- ❌ `https://api.trigger.dev/\u2007internal`
- ❌ `https://api.trigger.dev/\u202Finternal`
- ❌ `https://api.trigger.dev/\u205Finternal`
- ❌ `https://api.trigger.dev/\u180Einternal`
- ❌ `https://api.trigger.dev/\u3000internal`
- ❌ `https://api.trigger.dev/\u2028internal`
- ❌ `https://api.trigger.dev/\u2029internal`
+2
View File
@@ -32,6 +32,8 @@
confirmed empty-after-trim values still throw `baseURL must not be empty`.
- Expanded unicode whitespace coverage with `\u2007` (figure space) and `\u205F` (medium mathematical space)
across internal-whitespace rejection, wrapper trimming acceptance, and empty-after-trim validation.
- Expanded invisible-separator coverage to reject `\u180E` (mongolian vowel separator) in both
internal and wrapper `baseURL` positions.
- Documented that `HTTP://` and `HTTPS://` are accepted (case-insensitive protocol matching).
- Added deterministic validation ordering for multi-issue baseURL values
(internal whitespace → protocol → query/hash → credentials).
+2
View File
@@ -186,6 +186,7 @@ Examples:
-`\u200Bhttps://api.trigger.dev/custom-prefix/\u200B` (zero-width-space wrappers are rejected)
-`\u200Chttps://api.trigger.dev/custom-prefix/\u200C` (zero-width-non-joiner wrappers are rejected)
-`\u200Dhttps://api.trigger.dev/custom-prefix/\u200D` (zero-width-joiner wrappers are rejected)
-`\u180Ehttps://api.trigger.dev/custom-prefix/\u180E` (mongolian-vowel-separator wrappers are rejected)
-`https://api.trigger.dev?foo=bar` (query string)
-`https://api.trigger.dev#fragment` (hash fragment)
-`https://user:pass@api.trigger.dev` (credentials)
@@ -212,6 +213,7 @@ Examples:
-`https://api.trigger.dev/\u2007internal` (internal figure-space characters)
-`https://api.trigger.dev/\u202Finternal` (internal narrow no-break space characters)
-`https://api.trigger.dev/\u205Finternal` (internal medium-mathematical-space characters)
-`https://api.trigger.dev/\u180Einternal` (internal mongolian-vowel-separator characters)
-`https://api.trigger.dev/\u3000internal` (internal ideographic-space characters)
-`https://api.trigger.dev/\u2028internal` (internal line-separator characters)
-`https://api.trigger.dev/\u2029internal` (internal paragraph-separator characters)
+44
View File
@@ -950,6 +950,17 @@ describe("TriggerChatTransport", function () {
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws when baseURL contains internal mongolian-vowel-separator characters", function () {
expect(function () {
new TriggerChatTransport({
task: "chat-task",
accessToken: "pk_trigger",
baseURL: "https://api.trigger.dev/\u180Einternal",
stream: "chat-stream",
});
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws when baseURL contains internal line-separator characters", function () {
expect(function () {
new TriggerChatTransport({
@@ -1027,6 +1038,17 @@ describe("TriggerChatTransport", function () {
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws when baseURL is wrapped with mongolian-vowel-separator characters", function () {
expect(function () {
new TriggerChatTransport({
task: "chat-task",
accessToken: "pk_trigger",
baseURL: "\u180Ehttps://api.trigger.dev/custom-prefix/\u180E",
stream: "chat-stream",
});
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws when baseURL contains internal zero-width-non-joiner characters", function () {
expect(function () {
new TriggerChatTransport({
@@ -4043,6 +4065,17 @@ describe("TriggerChatTransport", function () {
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws from factory when baseURL contains internal mongolian-vowel-separator characters", function () {
expect(function () {
createTriggerChatTransport({
task: "chat-task",
accessToken: "pk_trigger",
baseURL: "https://api.trigger.dev/\u180Einternal",
stream: "chat-stream",
});
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws from factory when baseURL contains internal line-separator characters", function () {
expect(function () {
createTriggerChatTransport({
@@ -4120,6 +4153,17 @@ describe("TriggerChatTransport", function () {
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws from factory when baseURL is wrapped with mongolian-vowel-separator characters", function () {
expect(function () {
createTriggerChatTransport({
task: "chat-task",
accessToken: "pk_trigger",
baseURL: "\u180Ehttps://api.trigger.dev/custom-prefix/\u180E",
stream: "chat-stream",
});
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws from factory when baseURL contains internal zero-width-non-joiner characters", function () {
expect(function () {
createTriggerChatTransport({
+1 -1
View File
@@ -459,7 +459,7 @@ const BASE_URL_VALIDATION_ERRORS = {
// Includes standard whitespace plus common invisible separator/control marks
// that can make URLs look valid while behaving unexpectedly.
const INTERNAL_WHITESPACE_REGEX = /[\s\u200B\u200C\u200D\u2060\uFEFF]/u;
const INTERNAL_WHITESPACE_REGEX = /[\s\u180E\u200B\u200C\u200D\u2060\uFEFF]/u;
function resolvePayloadMapper<
UI_MESSAGE extends UIMessage,