Skip to content

Conversation

@pedroccastro
Copy link
Contributor

What does this PR do?

Adds URL validation for organization logo fields to ensure only allowed URLs are accepted for server-side fetching.

Changes

Layer File(s) Change
Lib ssrfProtection.ts URL validation utility with protocol, hostname, and IP checks
Lib zod/ssrfSafeUrl.ts Zod schema for tRPC validation
API v2 ssrfSafeUrlValidator.ts class-validator for DTOs
API v2 create-team.input.ts, update-team.input.ts Replace @IsUrl() with URL validator
tRPC update.schema.ts Add URL validation to logo fields
Route logo/route.ts Add validation before fetching external URLs

Validation rules

  • Only HTTPS URLs allowed (HTTP blocked)
  • Image data URLs (data:image/*) allowed
  • Private IP ranges blocked (RFC1918)
  • Cloud metadata endpoints blocked
  • Graceful fallback to default logo on validation failure

How should this be tested?

  1. Update organization with valid logo URL → should work
  2. Update organization with http:// URL → should be rejected
  3. Update organization with data:image/png;base64,... → should work
  4. Access /api/logo with invalid external URL → should fallback to default logo
  5. Run tests: yarn vitest run packages/lib/ssrfProtection.test.ts

Mandatory Tasks

  • I have self-reviewed the code
  • N/A I have updated the developer docs
  • I confirm automated tests are in place

- Add URL validation utility for server-side fetched URLs
- Validate logo URLs in tRPC organization schema
- Validate logo URLs in API v2 team DTOs
- Add graceful fallback in logo route for invalid URLs
- Only allow HTTPS and image data URLs
- Add unit tests for URL validation
@pedroccastro pedroccastro requested a review from a team as a code owner January 7, 2026 05:41
@graphite-app graphite-app bot added foundation core area: core, team members only labels Jan 7, 2026
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.

2 issues found across 9 files

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/lib/ssrfProtection.ts">

<violation number="1" location="packages/lib/ssrfProtection.ts:24">
P1: Missing RFC 6598 Carrier-Grade NAT range (100.64.0.0/10) in private IP patterns. This range is used in cloud environments (AWS VPC NAT, GCP internal services) and could be exploited for SSRF attacks to access internal infrastructure.</violation>
</file>

<file name="apps/api/v2/src/modules/teams/teams/inputs/update-team.input.ts">

<violation number="1" location="apps/api/v2/src/modules/teams/teams/inputs/update-team.input.ts:20">
P2: Missing `@IsString()` decorator. The custom `SSRFSafeUrlValidator` assumes string input but doesn't perform type checking. If a non-string value is passed, `validateUrlForSSRFSync` will throw when calling `urlString.startsWith()`. Add `@IsString()` before `@Validate(SSRFSafeUrlValidator)` to maintain the type safety that `@IsUrl()` provided.</violation>
</file>

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

- Add RFC 6598 CGNAT range (100.64.0.0/10) to blocked IPs
- Add @IsString() decorator before custom URL validators
- Add boundary tests for new IP range
@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 10, 2026 10:09am
cal Ignored Ignored Jan 10, 2026 10:09am
cal-companion Ignored Ignored Preview Jan 10, 2026 10:09am
cal-eu Ignored Ignored Jan 10, 2026 10:09am

Copy link
Contributor

@keithwillcode keithwillcode left a comment

Choose a reason for hiding this comment

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

@pedroccastro Checks are failing

@github-actions github-actions bot marked this pull request as draft January 7, 2026 10:22
   - Export validateUrlForSSRFSync via @calcom/platform-libraries
   - Fix nullable/optional order in Zod schema
@pedroccastro pedroccastro marked this pull request as ready for review January 7, 2026 12:00
@pedroccastro pedroccastro requested a review from a team as a code owner January 7, 2026 12:00
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.

3 issues found across 10 files

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/lib/zod/ssrfSafeUrl.ts">

<violation number="1" location="packages/lib/zod/ssrfSafeUrl.ts:34">
P2: Empty string `""` bypasses SSRF validation due to falsy check. The comment says "null/undefined allowed" but `!url` also passes for empty strings. Use explicit check for null/undefined.</violation>
</file>

<file name="packages/lib/ssrfProtection.test.ts">

<violation number="1" location="packages/lib/ssrfProtection.test.ts:81">
P1: Missing test for `localhost` hostname bypass in SSRF protection. The sync validator cannot resolve DNS, so `localhost` must be explicitly blocked. Add a test case: `["https://localhost/logo.png", "Blocked hostname"]` and ensure the implementation includes `localhost` in `BLOCKED_HOSTNAMES`.</violation>
</file>

<file name="packages/lib/ssrfProtection.ts">

<violation number="1" location="packages/lib/ssrfProtection.ts:44">
P1: Security: `localhost` is missing from `BLOCKED_HOSTNAMES`, allowing SSRF bypass in the sync validation function. Since `validateUrlForSSRFSync` has no DNS resolution, URLs like `https://localhost/...` will pass validation and could be used to access local services when fetched server-side.</violation>
</file>

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

- Add localhost to BLOCKED_HOSTNAMES for sync validation
- Use explicit null check (url == null) instead of falsy check
@github-actions
Copy link
Contributor

github-actions bot commented Jan 7, 2026

E2E results are ready!

- Extract validateUrlCore() to eliminate duplication between sync/async versions
- Add JSDoc to all exported functions for better discoverability
- Remove redundant comments that repeated function names
- Simplify existing comments to be more concise
Previously if (!url) allowed empty strings to bypass validation.
Now explicitly checks for null/undefined only
Copy link
Contributor

@emrysal emrysal left a comment

Choose a reason for hiding this comment

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

Very cool! approved!

@emrysal emrysal merged commit d9aef5b into main Jan 8, 2026
47 of 48 checks passed
@emrysal emrysal deleted the fix/logo-url-validation branch January 8, 2026 22:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants