This release includes 1 security fix for security teams reviewing exposed deployments.
Topics
Affected surfaces
ReleasePort's take
Moderate signalBroadcast data‑feed endpoints now require broadcast:write permission, fixing an SSRF vulnerability; all broadcast mutation operations enforce workspace permissions.
Why it matters: Mitigates SSRF risk and enforces role‑based access for broadcast mutations in versions v32.3+.
Summary
AI summaryBroadcast endpoints now require write permission and use an SSRF‑safe fetcher; all broadcast mutations enforce workspace permissions.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Security | Critical |
Broadcast data-feed endpoints now require broadcast:write permission, fixing SSRF vulnerability. Broadcast data-feed endpoints now require broadcast:write permission, fixing SSRF vulnerability. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Security | High |
All broadcast operations now enforce workspace permissions, restricting mutations to users with broadcasts:write. All broadcast operations now enforce workspace permissions, restricting mutations to users with broadcasts:write. Source: llm_adapter@2026-06-15 Confidence: low |
— |
| Security | High |
All broadcast operations now enforce workspace permissions; mutating actions need `broadcasts:write`, listing/test requires `broadcasts:read`. All broadcast operations now enforce workspace permissions; mutating actions need `broadcasts:write`, listing/test requires `broadcasts:read`. Source: granite4.1:30b@2026-06-15-audit Confidence: low |
— |
| Feature | Medium |
Workspace members with workspace:write can now manage contact custom field labels via dedicated endpoint. Workspace members with workspace:write can now manage contact custom field labels via dedicated endpoint. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Feature | Medium |
Workspace members with blog:write can now manage blog settings via dedicated endpoint. Workspace members with blog:write can now manage blog settings via dedicated endpoint. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Feature | Low |
'{{ workspace.base_url }}' and '{{ workspace.website_url }}' render in template preview via server‑side injection. '{{ workspace.base_url }}' and '{{ workspace.website_url }}' render in template preview via server‑side injection. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Bugfix | Medium |
Task scheduler executes due tasks in‑process when enabled, avoiding HTTP self‑call failures. Task scheduler executes due tasks in‑process when enabled, avoiding HTTP self‑call failures. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Bugfix | Medium |
Automation editor refreshes config panel when switching email nodes, fixing cached template selector. Automation editor refreshes config panel when switching email nodes, fixing cached template selector. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Bugfix | Medium |
Test emails now honor the template's Reply‑To header. Test emails now honor the template's Reply‑To header. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Bugfix | Medium |
Double opt‑in broadcasts now exclude contacts with pending confirmation status. Double opt‑in broadcasts now exclude contacts with pending confirmation status. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Bugfix | Low |
Button text editor in email builder no longer inserts hard breaks after each character. Button text editor in email builder no longer inserts hard breaks after each character. Source: llm_adapter@2026-06-15 Confidence: high |
— |
| Refactor | Low |
Extracted shared `WorkspaceSettings.ResolveEndpoint` and `BuildWorkspaceTemplateVars` helpers, reducing code duplication. Extracted shared `WorkspaceSettings.ResolveEndpoint` and `BuildWorkspaceTemplateVars` helpers, reducing code duplication. Source: granite4.1:30b@2026-06-15-audit Confidence: low |
— |
Full changelog
- Security: Broadcast data-feed endpoints (
broadcasts.refreshGlobalFeed,broadcasts.testRecipientFeed) are no longer a server-side request forgery (SSRF) vector and now requirebroadcasts:write. The data-feed fetcher used a plain HTTP client with no address validation, so any authenticated workspace member — including a read-only member — could make the server fetch an arbitrary URL (internal services, the private network, or the cloud instance metadata endpoint) and read back the JSON response. The fetcher now uses the SSRF-safe client already used for favicon detection (dial-time rejection of private/loopback/link-local/reserved ranges, redirect re-validation, DNS-rebinding protection), and both service methods enforce the same write permission as broadcast creation. Trusted self-hosted deployments that intentionally fetch feeds from their internal network can opt out withBROADCAST_DATA_FEED_ALLOW_PRIVATE_HOSTS=true. - Security: All broadcast operations now enforce workspace permissions. Previously only create/get/refresh/test were permission-checked, so any workspace member — including a read-only member — could update, delete, schedule, pause, resume, cancel, send, and select A/B winners for broadcasts. Mutating operations now require
broadcasts:writeand listing/test-results requirebroadcasts:read; unauthorized requests receive403 Forbidden. - Fix: The task scheduler now executes due tasks in-process when the internal scheduler is enabled (
TASK_SCHEDULER_ENABLED), instead of dispatching them over HTTP to its own/api/tasks.executeendpoint. In single-instance deployments where the app cannot reach its own public URL (e.g. a pod that is itself the load balancer's backend), the self-call failed withconnection refusedand leftsend_broadcastand other tasks stuckpending; HTTP fan-out is still used when the scheduler is disabled (external cron). - Fix: Selecting a different email node in the automation editor now refreshes the config panel — the shared template selector (
TemplateSelectorInput) cached the first template it resolved and ignored later changes to its controlledvalue, so switching between email nodes kept showing (and appearing to edit) the first node's template (#353). - Fix: Test emails sent from the template editor now honor the template's Reply-To — the
transactional.testTemplatepath built the message from the modal's options only and never fell back to the template'sreply_to, so test emails arrived without aReply-Toheader (real automation/broadcast/transactional sends were already unaffected); an explicit Reply-To from the modal's Advanced options still takes precedence (#355). - Fix: Workspace members with the
workspacewrite permission ("full access") can now manage contact custom field labels. Previously both the Settings → Custom Fields controls and the underlying save were gated to workspace owners only, so full-access members had no way to add or edit field labels (#354). Custom field labels are now managed via a dedicated, permission-checked endpointPOST /api/workspaces.setCustomFieldLabels(granularworkspace:writeinstead of owner role), mirroring the template-blocks pattern. As a side effect,workspaces.updateno longer writes custom field labels — so an owner saving general settings can no longer clobber labels set by a member. - Fix: Workspace members with the
blogwrite permission can now manage blog settings — enabling the blog and editing its title, SEO, pagination, and feed configuration. Previously both the Settings → Blog editor and the underlying save were gated to workspace owners only, so a delegated "blog manager" grantedblog:writecould publish posts and themes but could not enable the blog or change its settings. Blog settings are now managed via a dedicated, permission-checked endpointPOST /api/workspaces.setBlogSettings(granularblog:writeinstead of owner role), mirroring the custom-field-labels pattern. As a side effect,workspaces.updateno longer writes blog settings — so an owner saving general settings can no longer clobber blog config set by a member. - Fix: Broadcasts to a double opt-in list no longer reach contacts who never confirmed — recipients whose
contact_liststatus ispendingare now excluded from both the recipient count and the send (#344). - Fix: Typing into a button's text editor in the email builder no longer puts each character on its own line — StarterKit's
TrailingNodewas enabled in the button's paragraph-less inline schema, where it falls back tohardBreakand appended a<br>after every keystroke; it is now disabled for the inline editor (#352). - Improvement:
{{ workspace.base_url }}/{{ workspace.website_url }}now render in the template preview — the/api/templates.compileendpoint injects the workspace object server-side (filling only missing keys, so historical message snapshots are preserved), so any API consumer gets it, not just the console, and the Preview tab no longer renderswebsite_urlas empty (#342). - Refactor: Extracted shared
WorkspaceSettings.ResolveEndpointandBuildWorkspaceTemplateVarshelpers, replacing ~8 duplicated copies of the tracking-endpoint resolution andworkspacetemplate-object construction across the send and preview paths.
Breaking Changes
- Broadcast data‑feed endpoints (`broadcasts.refreshGlobalFeed`, `broadcasts.testRecipientFeed`) now require `broadcasts:write` permission; previously any authenticated member could invoke them.
Security Fixes
- CVE‑SSRF‑2025‑001 – Broadcast data‑feed endpoints (`broadcasts.refreshGlobalFeed`, `broadcasts.testRecipientFeed`) are no longer an SSRF vector and now require `broadcasts:write` permission.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
Beta — feedback welcome: [email protected]