Reject internal whitespace in normalized baseURL values

Co-authored-by: Eric Allam <eric@trigger.dev>
This commit is contained in:
Cursor Agent
2026-02-15 05:32:31 +00:00
parent e92a84e51e
commit 2644de574c
6 changed files with 37 additions and 0 deletions
+1
View File
@@ -9,5 +9,6 @@ Add a new `@trigger.dev/ai` package with:
- rich default task payloads (`chatId`, trigger metadata, messages, request context) with optional payload mapping
- reconnect-aware stream handling on top of Trigger.dev Realtime Streams v2
- strict `baseURL` normalization/validation (trimming, path-safe slash handling, absolute `http(s)` URLs only, no query/hash/credentials)
- rejection of internal whitespace characters in normalized `baseURL` values
- deterministic baseURL validation error ordering for multi-issue inputs (protocol → query/hash → credentials)
- explicit default `baseURL` behavior (`https://api.trigger.dev`) and case-insensitive `HTTP(S)` protocol acceptance
+2
View File
@@ -671,11 +671,13 @@ Examples:
- ❌ `https://user:pass@api.trigger.dev`
- ❌ `ftp://api.trigger.dev`
- ❌ `ws://api.trigger.dev` / `wss://api.trigger.dev`
- ❌ `https://api.trigger.dev/\ninternal`
Validation errors use these exact messages:
- `baseURL must not be empty`
- `baseURL must be a valid absolute URL`
- `baseURL must not contain internal whitespace characters`
- `baseURL must use http or https protocol`
- `baseURL must not include query parameters or hash fragments`
- `baseURL must not include username or password credentials`
+1
View File
@@ -26,6 +26,7 @@
- Added explicit validation that `baseURL` uses `http` or `https`.
- Added explicit validation that `baseURL` excludes query parameters and hash fragments.
- Added explicit validation that `baseURL` excludes username/password credentials.
- Added explicit validation that `baseURL` excludes internal whitespace characters.
- Documented that `HTTP://` and `HTTPS://` are accepted (case-insensitive protocol matching).
- Added deterministic validation ordering for multi-issue baseURL values
(protocol → query/hash → credentials).
+2
View File
@@ -178,11 +178,13 @@ Examples:
-`https://user:pass@api.trigger.dev` (credentials)
-`ftp://api.trigger.dev` (non-http protocol)
-`ws://api.trigger.dev` / `wss://api.trigger.dev` (websocket protocols are rejected)
-`https://api.trigger.dev/\ninternal` (internal whitespace characters)
Validation errors use these exact messages:
- `baseURL must not be empty`
- `baseURL must be a valid absolute URL`
- `baseURL must not contain internal whitespace characters`
- `baseURL must use http or https protocol`
- `baseURL must not include query parameters or hash fragments`
- `baseURL must not include username or password credentials`
+22
View File
@@ -720,6 +720,17 @@ describe("TriggerChatTransport", function () {
}).toThrowError("baseURL must be a valid absolute URL");
});
it("throws when baseURL contains internal whitespace characters", function () {
expect(function () {
new TriggerChatTransport({
task: "chat-task",
accessToken: "pk_trigger",
baseURL: "https://api.trigger.dev/\ninternal",
stream: "chat-stream",
});
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws when baseURL is a relative path", function () {
expect(function () {
new TriggerChatTransport({
@@ -3250,6 +3261,17 @@ describe("TriggerChatTransport", function () {
}).toThrowError("baseURL must be a valid absolute URL");
});
it("throws from factory when baseURL contains internal whitespace characters", function () {
expect(function () {
createTriggerChatTransport({
task: "chat-task",
accessToken: "pk_trigger",
baseURL: "https://api.trigger.dev/\ninternal",
stream: "chat-stream",
});
}).toThrowError("baseURL must not contain internal whitespace characters");
});
it("throws from factory when baseURL protocol is not http or https", function () {
expect(function () {
createTriggerChatTransport({
+9
View File
@@ -451,6 +451,7 @@ export function createTriggerChatTransport<
const BASE_URL_VALIDATION_ERRORS = {
empty: "baseURL must not be empty",
invalidAbsoluteUrl: "baseURL must be a valid absolute URL",
containsWhitespace: "baseURL must not contain internal whitespace characters",
invalidProtocol: "baseURL must use http or https protocol",
queryOrHash: "baseURL must not include query parameters or hash fragments",
credentials: "baseURL must not include username or password credentials",
@@ -474,6 +475,8 @@ function normalizeBaseUrl(baseURL: string) {
throw new Error(BASE_URL_VALIDATION_ERRORS.empty);
}
assertBaseUrlHasNoInternalWhitespace(normalizedBaseUrl);
let parsedBaseUrl: URL;
try {
parsedBaseUrl = new URL(normalizedBaseUrl);
@@ -488,6 +491,12 @@ function normalizeBaseUrl(baseURL: string) {
return normalizedBaseUrl;
}
function assertBaseUrlHasNoInternalWhitespace(baseUrl: string) {
if (/\s/.test(baseUrl)) {
throw new Error(BASE_URL_VALIDATION_ERRORS.containsWhitespace);
}
}
function assertValidBaseUrlProtocol(parsedBaseUrl: URL) {
if (
parsedBaseUrl.protocol !== "http:" &&