Skip to content

fix(security): fail closed on cron routes when CRON_SECRET is unset#29737

Open
TechGenius-Karan wants to merge 1 commit into
calcom:mainfrom
TechGenius-Karan:fix/cron-secret-fail-closed-29565
Open

fix(security): fail closed on cron routes when CRON_SECRET is unset#29737
TechGenius-Karan wants to merge 1 commit into
calcom:mainfrom
TechGenius-Karan:fix/cron-secret-fail-closed-29565

Conversation

@TechGenius-Karan

Copy link
Copy Markdown

What does this PR do?

Fixes #29565

when CRON_SECRET isn't set (it's not in .env.example), the template literal evaluates to "Bearer undefined" — so any request with that exact header string passes auth. same goes for the array-based routes where ["CRON_API_KEY_VALUE", "Bearer undefined"].includes(...) happily matches.

tasker routes (cleanup.ts, cron.ts) — added a !process.env.CRON_SECRET guard so the check fails closed when the secret is missing:

if (!process.env.CRON_SECRET || authHeader !== `Bearer ${process.env.CRON_SECRET}`) {

calendar cron routes — replaced the array .includes() with an explicit validKeys array that only gets populated when the env vars are actually set. if both are unset, validKeys is empty and the check rejects:

const validKeys: string[] = [];
if (process.env.CRON_API_KEY) validKeys.push(process.env.CRON_API_KEY);
if (process.env.CRON_SECRET) validKeys.push(`Bearer ${process.env.CRON_SECRET}`);
if (!validKeys.length || !validKeys.includes(`${apiKey}`)) { ... }

also added CRON_SECRET= to .env.example with a generation note, fixed the "Forbiden" typo in calendar-subscriptions/route.ts, and added a regression test for the fail-closed path (both env vars unset → 403).

Visual Demo (For contributors especially)

not applicable — auth logic fix, no UI changes.

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 if this PR makes changes that would require a documentation change. N/A — added CRON_SECRET to .env.example which is the relevant docs.
  • I confirm automated tests are in place that prove my fix is effective or that my feature works.

added a regression test to the existing route.test.ts that sends Bearer undefined with both env vars unset and asserts 403.

How should this be tested?

  1. unset CRON_SECRET in your env
  2. send Authorization: Bearer undefined to /api/tasks/cleanup or /api/tasks/cron
  3. should get 401 (before fix: 200)

or run the unit tests: cd apps/web && yarn test — the new test covers the fail-closed case.

Checklist

  • contributing guide read
  • 7 files changed, all in the cron auth layer
  • no new lint warnings introduced (pre-existing noProcessEnv warnings already present throughout these files)

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Welcome to Cal.diy, @TechGenius-Karan! Thanks for opening this pull request.

A few things to keep in mind:

  • This is Cal.diy, not Cal.com. Cal.diy is a community-driven, fully open-source fork of Cal.com licensed under MIT. Your changes here will be part of Cal.diy — they will not be deployed to the Cal.com production app.
  • Please review our Contributing Guidelines if you haven't already.
  • Make sure your PR title follows the Conventional Commits format.

A maintainer will review your PR soon. Thanks for contributing!

@github-actions github-actions Bot added 🐛 bug Something isn't working ❗️ .env changes contains changes to env variables labels Jul 7, 2026
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f262e782-6666-4a38-819e-02fd194bb501

📥 Commits

Reviewing files that changed from the base of the PR and between ca90ca2 and fbe6144.

📒 Files selected for processing (7)
  • .env.example
  • apps/web/app/api/cron/calendar-subscriptions-cleanup/route.ts
  • apps/web/app/api/cron/calendar-subscriptions/__tests__/route.test.ts
  • apps/web/app/api/cron/calendar-subscriptions/route.ts
  • apps/web/app/api/cron/selected-calendars/route.ts
  • packages/features/tasker/api/cleanup.ts
  • packages/features/tasker/api/cron.ts

📝 Walkthrough

Walkthrough

This change introduces a CRON_SECRET environment variable and refactors authorization logic across several cron-related routes and API handlers. Web app cron routes (calendar-subscriptions-cleanup, calendar-subscriptions, selected-calendars) now build a validKeys array from present environment variables and deny requests when empty or non-matching, with a corrected "Forbidden" message. Tasker API handlers (cleanup.ts, cron.ts) now explicitly reject requests when CRON_SECRET is unset. Test assertions were updated to match the corrected message and to cover the missing-secret case.

Changes

Area Change
.env.example Added CRON_SECRET variable documentation
Web cron routes Refactored authorization to use dynamic validKeys list; fixed "Forbidden" typo
Tasker API handlers Added explicit check for missing CRON_SECRET
Tests Updated assertions for corrected message; added missing-secret test case

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant CronRoute
  participant EnvVars

  Client->>CronRoute: Request with apiKey/authorization header
  CronRoute->>EnvVars: Read CRON_API_KEY, CRON_SECRET
  EnvVars-->>CronRoute: Values (may be unset)
  CronRoute->>CronRoute: Build validKeys list
  alt validKeys empty or apiKey not matched
    CronRoute-->>Client: 403/401 Forbidden/Unauthorized
  else apiKey matches
    CronRoute-->>Client: Proceed with handler logic
  end
Loading

Related issues: None specified.

Related PRs: None specified.

Suggested labels: security, bug-fix, cron

Suggested reviewers: None specified.

Poem

A rabbit hops through cron-lit code,
Securing keys along the road.
"Forbiden" fixed to "Forbidden" true,
CRON_SECRET joins the crew.
No empty keys shall pass this gate—
Hop on, the cron jobs run on schedule, straight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main security fix for cron routes failing closed when CRON_SECRET is unset.
Description check ✅ Passed The description matches the changeset and explains the auth fix, docs update, and regression test.
Linked Issues check ✅ Passed The changes satisfy [#29565] by failing closed when CRON_SECRET is missing, updating env docs, and adding regression coverage.
Out of Scope Changes check ✅ Passed The typo fix and test updates are directly related to the auth fix and not out of scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🐛 bug Something isn't working ❗️ .env changes contains changes to env variables size/M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cron/tasker endpoints authorize with "Bearer undefined" when CRON_SECRET is not set

1 participant