Skip to content

fix: security release 2026-07-06#4199

Merged
carderne merged 7 commits into
mainfrom
security-release/2026-07-06
Jul 9, 2026
Merged

fix: security release 2026-07-06#4199
carderne merged 7 commits into
mainfrom
security-release/2026-07-06

Conversation

@carderne

@carderne carderne commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Security release batch. Advisory details to be published with the release.

@changeset-bot

changeset-bot Bot commented Jul 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 49c951e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 28 packages
Name Type
trigger.dev Patch
@internal/dashboard-agent Patch
@trigger.dev/build Patch
@trigger.dev/core Patch
@trigger.dev/plugins Patch
@trigger.dev/python Patch
@trigger.dev/react-hooks Patch
@trigger.dev/redis-worker Patch
@trigger.dev/rsc Patch
@trigger.dev/schema-to-json Patch
@trigger.dev/sdk Patch
@trigger.dev/database Patch
@trigger.dev/otlp-importer Patch
@trigger.dev/rbac Patch
@trigger.dev/sso Patch
@internal/cache Patch
@internal/clickhouse Patch
@internal/llm-model-catalog Patch
@internal/redis Patch
@internal/replication Patch
@internal/run-engine Patch
@internal/run-store Patch
@internal/schedule-engine Patch
@internal/testcontainers Patch
@internal/tracing Patch
@internal/tsql Patch
@internal/zod-worker Patch
@internal/sdk-compat-tests Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@carderne carderne marked this pull request as ready for review July 9, 2026 11:35
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR bundles a broad set of security hardening changes across the webapp: SSRF-safe webhook validation and fetch wrapper for alert delivery, stricter URL schemas for platform notifications, tenant/environment scoping for batch, trigger, replay, and idempotency lookups, per-table query authorization via a new TRQL table detector, rate limiting for the ai-title endpoint, prompt override source normalization, secret redaction in logs (environments, JWT context, Slack integrations, worker headers), same-origin/CSRF checks for impersonation and batch-resume redirects, an email allowlist pattern matcher, an extracted invite role ladder utility, worker group project access checks, Google email verification enforcement, a refactored/testable MFA rate limiter, an extracted removeTeamMember module, and a CLI fix propagating the MCP server's --dev-only flag. Extensive new unit and integration tests accompany each change.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 43.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The description is far too brief and omits the required template sections and issue reference. Add the Closes # issue line, checklist, Testing, Changelog, and Screenshots sections per the template.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title matches the changeset and clearly signals a security release batch.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch security-release/2026-07-06

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.server-changes/account-access-control-hardening.md (1)

6-7: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Rewrite the changelog description for users, avoiding internal terms.

The description uses "RBAC" and "impersonation" — internal/infrastructure terms that users won't understand. As per coding guidelines, .server-changes/ notes should be written for users, leading with what changed in one plain sentence and avoiding internal tool or infrastructure names.

✍️ Proposed rewrite
-Harden account and access-control handling across auth, RBAC, org membership, and impersonation
+Strengthened security for account access, organization membership, and administrative controls

Source: Coding guidelines

🧹 Nitpick comments (4)
.changeset/mcp-thread-dev-only-flag.md (1)

5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rewrite this changeset in user-facing language.

This reads like an internal implementation note. Please lead with the user-visible behavior and avoid tool-internal phrasing.

Source: Coding guidelines

apps/webapp/test/safeWebhookFetch.test.ts (1)

11-13: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Add a positive test for http:// scheme.

The test name says "accepts a public http(s) URL" but only asserts https://. The rejection tests at lines 21–61 use http:// but expect rejection based on host, not scheme — so they don't prove http:// is accepted. Adding one assertion closes this gap and matches the test's stated scope.

✨ Suggested addition
   it("accepts a public http(s) URL given as an IP literal (no DNS needed)", async () => {
     await expect(assertSafeWebhookUrl("https://93.184.216.34/hook")).resolves.toBeInstanceOf(URL);
+    await expect(assertSafeWebhookUrl("http://93.184.216.34/hook")).resolves.toBeInstanceOf(URL);
   });
apps/webapp/test/detectQueryTables.test.ts (1)

1-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a test for top-level UNION/INTERSECT (select_set_query)

The code handles select_set_query at the top level (detectQueryTables.ts Lines 109-110), but no test covers it. A UNION reading from different tables in each branch (e.g., SELECT * FROM runs UNION SELECT * FROM tasks) is an important authorization case — if visitSelectSet or the top-level dispatch breaks, every branch table silently goes undetected.

♻️ Suggested test addition
   it("returns null for an unparseable query (caller denies by default)", () => {
     expect(detectQueryTables("definitely not a valid query !!!", allowed)).toBeNull();
   });
+
+  it("detects tables across UNION branches", () => {
+    expect(
+      sorted(detectQueryTables("SELECT * FROM runs UNION SELECT * FROM tasks", allowed))
+    ).toEqual(["runs", "tasks"]);
+  });
 });
apps/webapp/app/v3/services/dependentAttemptScope.ts (1)

9-17: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider consolidating with attemptInEnvironmentWhere.

dependentAttemptWhere is functionally identical to attemptInEnvironmentWhere in triggerV1Scoping.ts — both return { friendlyId, taskRun: { runtimeEnvironmentId: environmentId } }. If the schema for attempt lookups changes, both must be updated in sync. Consider having one re-export or delegate to the other, unless the separate domain naming is intentionally preferred for readability.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 859bda45-19b9-4073-b4fb-56de63ef5e4f

📥 Commits

Reviewing files that changed from the base of the PR and between bb450e6 and 49c951e.

📒 Files selected for processing (88)
  • .changeset/mcp-thread-dev-only-flag.md
  • .server-changes/account-access-control-hardening.md
  • .server-changes/harden-alert-webhook-and-notification-urls.md
  • .server-changes/query-and-api-endpoint-hardening.md
  • .server-changes/redact-secrets-from-logs.md
  • .server-changes/reject-cross-project-replay-environment.md
  • .server-changes/scope-run-batch-trigger-to-tenant.md
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/models/member.server.ts
  • apps/webapp/app/models/orgIntegration.server.ts
  • apps/webapp/app/models/removeTeamMember.server.ts
  • apps/webapp/app/models/safeIntegrationLog.ts
  • apps/webapp/app/models/slackOAuthResultLog.ts
  • apps/webapp/app/models/user.server.ts
  • apps/webapp/app/routes/_app.@.orgs.$organizationSlug.$.ts
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.invite/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.alerts.new/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.errors/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings.team/route.tsx
  • apps/webapp/app/routes/api.v1.projects.$projectRef.alertChannels.ts
  • apps/webapp/app/routes/api.v1.prompts.$slug.override.ts
  • apps/webapp/app/routes/api.v1.query.ts
  • apps/webapp/app/routes/login.mfa/route.tsx
  • apps/webapp/app/routes/resources.batches.$batchId.check-completion.ts
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query.ai-title.tsx
  • apps/webapp/app/runEngine/concerns/idempotencyKeys.server.ts
  • apps/webapp/app/services/apiAuth.server.ts
  • apps/webapp/app/services/googleAuth.server.ts
  • apps/webapp/app/services/googleEmailVerification.ts
  • apps/webapp/app/services/mfa/mfaRateLimiter.server.ts
  • apps/webapp/app/services/mfa/mfaRateLimiterGlobal.server.ts
  • apps/webapp/app/services/platformNotifications.server.ts
  • apps/webapp/app/services/rateLimiter.server.ts
  • apps/webapp/app/services/rateLimiterCore.server.ts
  • apps/webapp/app/services/safeEnvironmentLog.ts
  • apps/webapp/app/services/safeRequestLogContext.ts
  • apps/webapp/app/utils/email.ts
  • apps/webapp/app/utils/emailPattern.ts
  • apps/webapp/app/utils/inviteRoleLadder.ts
  • apps/webapp/app/utils/sameOriginNavigation.ts
  • apps/webapp/app/utils/sanitizeUrl.ts
  • apps/webapp/app/v3/detectQueryTables.ts
  • apps/webapp/app/v3/services/aiTitleRateLimiter.server.ts
  • apps/webapp/app/v3/services/alerts/createAlertChannel.server.ts
  • apps/webapp/app/v3/services/alerts/deliverAlert.server.ts
  • apps/webapp/app/v3/services/alerts/deliverErrorGroupAlert.server.ts
  • apps/webapp/app/v3/services/alerts/safeWebhookFetch.server.ts
  • apps/webapp/app/v3/services/alerts/safeWebhookUrl.server.ts
  • apps/webapp/app/v3/services/batchRunAccess.server.ts
  • apps/webapp/app/v3/services/batchTriggerV3.server.ts
  • apps/webapp/app/v3/services/dependentAttemptScope.ts
  • apps/webapp/app/v3/services/promptOverrideSource.ts
  • apps/webapp/app/v3/services/promptService.server.ts
  • apps/webapp/app/v3/services/replayTaskRun.server.ts
  • apps/webapp/app/v3/services/triggerTaskV1.server.ts
  • apps/webapp/app/v3/services/triggerV1Scoping.ts
  • apps/webapp/app/v3/services/worker/sanitizeWorkerHeaders.ts
  • apps/webapp/app/v3/services/worker/workerGroupAccess.ts
  • apps/webapp/app/v3/services/worker/workerGroupService.server.ts
  • apps/webapp/app/v3/services/worker/workerGroupTokenService.server.ts
  • apps/webapp/test/aiTitleRateLimiter.test.ts
  • apps/webapp/test/batchRunAccess.test.ts
  • apps/webapp/test/dependentAttemptScope.test.ts
  • apps/webapp/test/detectQueryTables.test.ts
  • apps/webapp/test/emailPattern.test.ts
  • apps/webapp/test/engine/idempotencyParentRunScope.test.ts
  • apps/webapp/test/googleEmailVerification.test.ts
  • apps/webapp/test/inviteRoleLadder.test.ts
  • apps/webapp/test/mfaRateLimiter.test.ts
  • apps/webapp/test/promptOverrideSource.test.ts
  • apps/webapp/test/removeTeamMember.test.ts
  • apps/webapp/test/replayTaskRunEnvironmentScoping.test.ts
  • apps/webapp/test/safeEnvironmentLog.test.ts
  • apps/webapp/test/safeIntegrationLog.test.ts
  • apps/webapp/test/safeRequestLogContext.test.ts
  • apps/webapp/test/safeWebhookFetch.test.ts
  • apps/webapp/test/safeWebhookUrl.test.ts
  • apps/webapp/test/sameOriginNavigation.test.ts
  • apps/webapp/test/sanitizeUrl.test.ts
  • apps/webapp/test/sanitizeWorkerHeaders.test.ts
  • apps/webapp/test/slackOAuthResultLog.test.ts
  • apps/webapp/test/triggerV1Scoping.test.ts
  • apps/webapp/test/workerGroupAccess.test.ts
  • internal-packages/llm-model-catalog/src/defaultPrices.ts
  • internal-packages/llm-model-catalog/src/modelCatalog.ts
  • packages/cli-v3/src/commands/mcp.ts
  • packages/cli-v3/src/mcp/contextOptions.test.ts
  • packages/cli-v3/src/mcp/contextOptions.ts
💤 Files with no reviewable changes (1)
  • apps/webapp/app/models/member.server.ts

@carderne carderne enabled auto-merge (squash) July 9, 2026 11:56
@carderne carderne merged commit 34b1a18 into main Jul 9, 2026
92 of 94 checks passed
@carderne carderne deleted the security-release/2026-07-06 branch July 9, 2026 11:58
@github-actions github-actions Bot mentioned this pull request Jul 9, 2026
carderne pushed a commit that referenced this pull request Jul 9, 2026
## Summary
4 improvements, 5 bug fixes.

## Improvements
- Add SDK and API client helpers for run bulk actions.
([#4105](#4105))
- Large batch payloads now offload to object storage instead of riding
inline in the trigger request. `batchTrigger` and `batchTriggerAndWait`
(and the by-id and by-task variants) offload any per-item payload over
128KB before sending, the same way single `trigger` and `triggerAndWait`
already do, so a big batch no longer blows past the API body limit.
([#4165](#4165))
- Removed internal helpers that were only used by the end-of-life v3
self-hosted compute providers.
([#4194](#4194))
- Add an `onEvent` callback to `TriggerChatTransport` /
`useTriggerChatTransport` that emits typed lifecycle events for sends,
stream connects, first chunk, and turn completion. Send-success metrics,
time-to-first-token, and "sent but never answered" watchdogs become a
few lines of client code.
([#4187](#4187))
  
  ```ts
  onEvent: (event) => {
if (event.type === "message-sent") metrics.timing("chat.send_ms",
event.durationMs);
if (event.type === "first-chunk") metrics.timing("chat.ttft_ms",
event.sinceSendMs ?? 0);
  },
  ```

## Bug fixes
- fix(cli): honor the MCP server's `--dev-only` flag
([#4199](#4199))
- Fix chat turns that throw (for example from an `onTurnStart` hook)
leaking their message listener, which lost or duplicated messages sent
during later turns.
([#4176](#4176))
- Fix `chat.agent` and `chat.createSession` permanently dropping user
messages when several arrived during a single turn: every buffered
message is now dispatched as its own turn instead of only the first.
([#4176](#4176))
- Fix chat continuation runs replaying already-answered messages: turns
delivered while the run was suspended now advance the session.in resume
cursor, so a new run picks up exactly where the previous one left off.
([#4176](#4176))
- Fix `chat.createSession` swallowing a message sent shortly after
stopping a turn: the turn's message listener now detaches when the
stream settles, so those messages run as the next turn.
([#4176](#4176))

<details>
<summary>Raw changeset output</summary>

# Releases
## @trigger.dev/build@4.5.2

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.2`
## trigger.dev@4.5.2

### Patch Changes

- fix(cli): honor the MCP server's `--dev-only` flag
([#4199](#4199))
- Updated dependencies:
  - `@trigger.dev/core@4.5.2`
  - `@trigger.dev/build@4.5.2`
  - `@trigger.dev/schema-to-json@4.5.2`
## @trigger.dev/core@4.5.2

### Patch Changes

- Add SDK and API client helpers for run bulk actions.
([#4105](#4105))
- Large batch payloads now offload to object storage instead of riding
inline in the trigger request. `batchTrigger` and `batchTriggerAndWait`
(and the by-id and by-task variants) offload any per-item payload over
128KB before sending, the same way single `trigger` and `triggerAndWait`
already do, so a big batch no longer blows past the API body limit.
([#4165](#4165))
- Removed internal helpers that were only used by the end-of-life v3
self-hosted compute providers.
([#4194](#4194))
## @trigger.dev/python@4.5.2

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.2`
  - `@trigger.dev/sdk@4.5.2`
  - `@trigger.dev/build@4.5.2`
## @trigger.dev/react-hooks@4.5.2

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.2`
## @trigger.dev/redis-worker@4.5.2

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.2`
## @trigger.dev/rsc@4.5.2

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.2`
## @trigger.dev/schema-to-json@4.5.2

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.2`
## @trigger.dev/sdk@4.5.2

### Patch Changes

- Add SDK and API client helpers for run bulk actions.
([#4105](#4105))
- Fix chat turns that throw (for example from an `onTurnStart` hook)
leaking their message listener, which lost or duplicated messages sent
during later turns.
([#4176](#4176))
- Fix `chat.agent` and `chat.createSession` permanently dropping user
messages when several arrived during a single turn: every buffered
message is now dispatched as its own turn instead of only the first.
([#4176](#4176))
- Fix chat continuation runs replaying already-answered messages: turns
delivered while the run was suspended now advance the session.in resume
cursor, so a new run picks up exactly where the previous one left off.
([#4176](#4176))
- Fix `chat.createSession` swallowing a message sent shortly after
stopping a turn: the turn's message listener now detaches when the
stream settles, so those messages run as the next turn.
([#4176](#4176))
- Add an `onEvent` callback to `TriggerChatTransport` /
`useTriggerChatTransport` that emits typed lifecycle events for sends,
stream connects, first chunk, and turn completion. Send-success metrics,
time-to-first-token, and "sent but never answered" watchdogs become a
few lines of client code.
([#4187](#4187))

  ```ts
  onEvent: (event) => {
if (event.type === "message-sent") metrics.timing("chat.send_ms",
event.durationMs);
if (event.type === "first-chunk") metrics.timing("chat.ttft_ms",
event.sinceSendMs ?? 0);
  },
  ```

- Large batch payloads now offload to object storage instead of riding
inline in the trigger request. `batchTrigger` and `batchTriggerAndWait`
(and the by-id and by-task variants) offload any per-item payload over
128KB before sending, the same way single `trigger` and `triggerAndWait`
already do, so a big batch no longer blows past the API body limit.
([#4165](#4165))
- Updated dependencies:
  - `@trigger.dev/core@4.5.2`
## @trigger.dev/plugins@4.5.2

### Patch Changes

- Updated dependencies:
  - `@trigger.dev/core@4.5.2`

</details>

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

3 participants