Skip to content

Comments

feat: allow link cloaking for Organization accounts in workflow emails#26528

Merged
PeerRich merged 11 commits intomainfrom
devin/org-link-cloaking-1767773716
Jan 16, 2026
Merged

feat: allow link cloaking for Organization accounts in workflow emails#26528
PeerRich merged 11 commits intomainfrom
devin/org-link-cloaking-1767773716

Conversation

@PeerRich
Copy link
Member

@PeerRich PeerRich commented Jan 7, 2026

What does this PR do?

This PR allows Organization accounts to use cloaked links (URL behind text) in workflow emails, while keeping the restriction for non-Organization accounts.

Context: Previously, PR #26292 prevented all link cloaking in workflow emails to help recipients identify potentially malicious URLs. This change relaxes that restriction for Organization accounts since they are paid accounts with lower spam/scam risk.

Changes:

  • Frontend: Conditionally allow the "link" toolbar item in the Editor for Organization accounts
  • Backend: Skip replaceCloakedLinksInHtml sanitization for Organization workflows
  • Repository: Include team.isOrganization in the workflow reminder query

Implementation Scope:

  • The organization check is implemented in EmailWorkflowService.handleSendEmailWorkflowTask (the main tasker-based scheduled email path)
  • Other email paths (emailReminderManager, deprecated scheduleEmailReminders.ts) default to sanitizing all links (safer behavior)
  • This is intentional: the main scheduled email flow respects org status, while edge cases default to the stricter security posture

Mandatory Tasks (DO NOT REMOVE)

  • I have self-reviewed the code (A decent size PR without self-review might be rejected).
  • I have updated the developer docs in /docs if this PR makes changes that would require a documentation change. N/A - no documentation changes needed.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

How should this be tested?

  1. Organization account test:

    • Log in as a user in an Organization
    • Create/edit a workflow with an email action
    • Verify the "link" toolbar button is available in the Editor
    • Add a cloaked link (e.g., <a href="https://example.com">Click here</a>)
    • Trigger the workflow and verify the email contains the cloaked link (not sanitized)
  2. Non-Organization account test:

    • Log in as a user NOT in an Organization
    • Create/edit a workflow with an email action
    • Verify the "link" toolbar button is NOT available in the Editor
    • If a cloaked link exists in the email body, verify it gets sanitized to show the full URL

Human Review Checklist

  • Verify the isOrganization prop in WorkflowStepContainer.tsx is derived from the same source as workflow.team?.isOrganization in the backend
  • Confirm WorkflowReminderRepository.findByIdIncludeStepAndWorkflow is the query used for tasker-based email sends
  • Verify the deprecated scheduleEmailReminders.ts still sanitizes all links (intentional - safer default)
  • Review security implications of allowing cloaked links for Organization accounts

Link to Devin run: https://app.devin.ai/sessions/c245edc8038c4ac99ae88d65cbe65b71
Requested by: peer@cal.com (@PeerRich)

Organization accounts are paid accounts with lower spam/scam risk, so they
are allowed to use cloaked links (URL behind text) in workflow emails.

Changes:
- Frontend: Allow 'link' toolbar item in Editor for Organization accounts
- Backend: Skip replaceCloakedLinksInHtml sanitization for Organization workflows
- Repository: Include team.isOrganization in workflow reminder query

Co-Authored-By: peer@cal.com <peer@cal.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@vercel
Copy link

vercel bot commented Jan 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

4 Skipped Deployments
Project Deployment Review Updated (UTC)
api-v2 Ignored Ignored Preview Jan 9, 2026 2:24pm
cal Ignored Ignored Jan 9, 2026 2:24pm
cal-companion Ignored Ignored Preview Jan 9, 2026 2:24pm
cal-eu Ignored Ignored Jan 9, 2026 2:24pm

@PeerRich PeerRich requested a review from CarinaWolli January 7, 2026 16:56
@PeerRich PeerRich requested a review from a team January 7, 2026 16:57
@PeerRich PeerRich marked this pull request as ready for review January 7, 2026 16:57
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 3 files

@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

E2E results are ready!

@github-actions
Copy link
Contributor

Devin AI is resolving merge conflicts

This PR has merge conflicts with the main branch. The existing Devin session has been notified to resolve them.

View Devin Session

Devin will:

  1. Merge the latest main into this branch
  2. Resolve any conflicts intelligently
  3. Run lint/type checks to ensure validity
  4. Push the resolved changes

If you prefer to resolve conflicts manually, you can close the Devin session and handle it yourself.

@pull-request-size pull-request-size bot added size/M and removed size/S labels Jan 15, 2026
@pull-request-size pull-request-size bot added size/L and removed size/M labels Jan 15, 2026
Copy link
Contributor

@Ryukemeister Ryukemeister left a comment

Choose a reason for hiding this comment

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

email reminders and workflow reminders were missing logic for enabling cloaked emails for orgs, updated the code to fix that. all good now!

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/features/ee/workflows/api/scheduleEmailReminders.ts">

<violation number="1" location="packages/features/ee/workflows/api/scheduleEmailReminders.ts:360">
P2: This change contradicts the stated security design in the PR description. The description explicitly says this deprecated file should "default to sanitizing all links (safer behavior)" as the intentional security posture for edge cases. Adding the organization check here allows cloaked links for organizations, which is inconsistent with that design. If the stricter default is intended for deprecated paths, remove these organization checks and let all emails have links sanitized in this file.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +360 to +363
const isOrganization = reminder.workflowStep?.workflow?.team?.isOrganization ?? false;
const processedEmailBody = isOrganization
? emailContent.emailBody
: replaceCloakedLinksInHtml(emailContent.emailBody);
Copy link
Contributor

Choose a reason for hiding this comment

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

P2: This change contradicts the stated security design in the PR description. The description explicitly says this deprecated file should "default to sanitizing all links (safer behavior)" as the intentional security posture for edge cases. Adding the organization check here allows cloaked links for organizations, which is inconsistent with that design. If the stricter default is intended for deprecated paths, remove these organization checks and let all emails have links sanitized in this file.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/features/ee/workflows/api/scheduleEmailReminders.ts, line 360:

<comment>This change contradicts the stated security design in the PR description. The description explicitly says this deprecated file should "default to sanitizing all links (safer behavior)" as the intentional security posture for edge cases. Adding the organization check here allows cloaked links for organizations, which is inconsistent with that design. If the stricter default is intended for deprecated paths, remove these organization checks and let all emails have links sanitized in this file.</comment>

<file context>
@@ -355,10 +355,17 @@ export async function handler(req: NextRequest) {
 
+          // Organization accounts are allowed to use cloaked links (URL behind text)
+          // since they are paid accounts with lower spam/scam risk
+          const isOrganization = reminder.workflowStep?.workflow?.team?.isOrganization ?? false;
+          const processedEmailBody = isOrganization
+            ? emailContent.emailBody
</file context>

Fix confidence (alpha): 8/10

Suggested change
const isOrganization = reminder.workflowStep?.workflow?.team?.isOrganization ?? false;
const processedEmailBody = isOrganization
? emailContent.emailBody
: replaceCloakedLinksInHtml(emailContent.emailBody);
const processedEmailBody = replaceCloakedLinksInHtml(emailContent.emailBody);

@github-actions
Copy link
Contributor

Devin AI is addressing Cubic AI's review feedback

A Devin session has been created to address the issues identified by Cubic AI.

View Devin Session

Copy link
Member

@sean-brydon sean-brydon left a comment

Choose a reason for hiding this comment

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

Fixed one of the queries to follow best practise.

LGTM

@PeerRich PeerRich merged commit fc518bf into main Jan 16, 2026
45 checks passed
@PeerRich PeerRich deleted the devin/org-link-cloaking-1767773716 branch January 16, 2026 08:33
devin-ai-integration bot added a commit that referenced this pull request Jan 27, 2026
This reverts the changes from PR #26292 and PR #26528 to restore
link cloaking functionality for all users.

The plan is to fight malicious links with Cloudflare URL Scanner
instead of restricting link cloaking to Organization accounts only.

Changes:
- Remove replaceCloakedLinksInHtml function and its usage
- Restore link toolbar item for all users in workflow editor
- Remove isOrganization checks from email workflow processing
- Delete the replaceCloakedLinksInHtml test file

Co-Authored-By: peer@cal.com <peer@cal.com>
PeerRich added a commit that referenced this pull request Jan 27, 2026
…#27289)

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants