Skip to content

Conversation

@github-actions
Copy link
Contributor

This is an automated pull request to release the candidate branch into production, which will trigger a deployment.
It was created by the [Production PR] action.

@comp-ai-code-review
Copy link

comp-ai-code-review bot commented Nov 26, 2025

🔒 Comp AI - Security Review

🔴 Risk Level: HIGH

OSV: 3 npm CVEs — xlsx (prototype pollution & ReDoS) v0.18.5; ai filetype whitelist bypass (fixed in 5.0.52). Code changes show SQL, header (cookie), and CSV/formula injection vectors.


📦 Dependency Vulnerabilities

🟠 NPM Packages (HIGH)

Risk Score: 8/10 | Summary: 2 high, 1 low CVEs found

Package Version CVE Severity CVSS Summary Fixed In
xlsx 0.18.5 GHSA-4r6h-8v6p-xvw6 HIGH N/A Prototype Pollution in sheetJS No fix yet
xlsx 0.18.5 GHSA-5pgg-2g8v-p4x9 HIGH N/A SheetJS Regular Expression Denial of Service (ReDoS) No fix yet
ai 5.0.0 GHSA-rwvc-j5jr-mgvh LOW N/A Vercel’s AI SDK's filetype whitelists can be bypassed when uploading files 5.0.52

🛡️ Code Security Analysis

View 7 file(s) with issues

🟡 apps/app/src/actions/organization/accept-invitation.ts (MEDIUM Risk)

# Issue Risk Level
1 Invite code has minimal validation (z.string() only) MEDIUM
2 No rate limiting on invite-code acceptance (brute-force risk) MEDIUM
3 Error details are logged and rethrown, risking sensitive info leakage MEDIUM
4 Potential race condition: concurrent accepts may create duplicate members or inconsistent state MEDIUM
5 Throwing new Error(error as string) may expose raw/internal error text MEDIUM

Recommendations:

  1. Tighten inviteCode validation: validate format/length (e.g., UUID or token regex) in the zod schema (z.string().uuid() or z.string().regex(...)).
  2. Add rate limiting / throttling on the invitation-completion action (per IP and per user) to mitigate brute-force attempts against invite codes.
  3. Avoid logging or returning raw error objects. Log full error details server-side (with sensitive fields redacted) but return a generic client-facing message (e.g., 'Unable to accept invitation').
  4. Do not rethrow the raw error to the client. Return a controlled error response or throw a generic Error('Internal server error') and provide an internal error id for support lookup.
  5. Wrap the invitation acceptance flow in a database transaction (or use an atomic UPSERT/conditional write) to ensure consistent state: create member, update invitation status, update session atomically.
  6. Add database constraints to guard against duplicates (e.g., unique(userId, organizationId) on members) so concurrent requests cannot create duplicate membership rows.
  7. Consider optimistic locking or conditional updates on the invitation record (e.g., update where status = 'pending') and check affected rows to detect concurrent acceptance and avoid races.
  8. Sanitize logged errors to avoid leaking PII (invite codes, emails, or internal IDs) and ensure logs are only accessible to authorized personnel.

🟡 apps/app/src/actions/tasks.ts (MEDIUM Risk)

# Issue Risk Level
1 User-controlled orgId used in cookie name (response header injection risk) MEDIUM
2 Cookie set without HttpOnly flag — readable by JavaScript MEDIUM
3 Cookie set without Secure flag — may be sent over HTTP MEDIUM
4 Cookie set without SameSite attribute — CSRF risk MEDIUM
5 orgId lacks strict validation/sanitization (special chars allowed) MEDIUM
6 No auth/authorization check before updating preference MEDIUM
7 No length limit on orgId allows oversized cookie names/values MEDIUM

Recommendations:

  1. Validate and whitelist orgId (e.g. /^[A-Za-z0-9_-]{1,64}$/) and enforce a max length to prevent oversized cookie names/values.
  2. Reject or sanitize characters that can affect HTTP headers (CR, LF) in orgId; when in doubt, use a safe encoding for the cookie name (e.g., base64 or a server-side canonical id) instead of raw user input.
  3. Set explicit cookie attributes when calling cookieStore.set: httpOnly: true, secure: true (or conditional for dev), sameSite: 'lax' (or 'strict' per UX), and a reasonable maxAge/path.
  4. Encode cookie name/value using a safe encoding (e.g., encodeURIComponent or server-generated identifier) so special characters cannot break headers.
  5. Enforce authentication and authorization: ensure the requester is authenticated and permitted to set preferences for the given orgId (e.g., membership/ownership checks).
  6. Add server-side length limits and fail-fast validation in the action input schema (z.string().max(64).regex(...)).
  7. Log and monitor unexpected or rejected orgId values to detect abuse or attempted header injection.

🟡 apps/app/src/app/(app)/[orgId]/people/all/actions/checkMemberStatus.ts (MEDIUM Risk)

# Issue Risk Level
1 Missing input validation for email and organizationId MEDIUM
2 User enumeration via different responses for missing vs existing emails MEDIUM
3 Internal memberId leaked in response payloads MEDIUM

Recommendations:

  1. Add explicit input validation and normalization for email and organizationId (e.g., validate email format, enforce organizationId pattern such as UUID). Reject or sanitize invalid inputs server-side before DB queries.
  2. Avoid user enumeration: return a normalized/opaque response for existence checks (for example always return success with a generic message/state or a 204) or perform checks asynchronously and not disclose whether an email exists.
  3. Do not return internal identifiers in client responses. Omit memberId or return a randomized/mapped token if a reference is required for client flows.
  4. Harden authorization checks: ensure role is present and type-checked before calling .includes (e.g., Array.isArray(role) or typeof role === 'string') and use an explicit allowlist for allowed roles.
  5. Add rate limiting and logging for membership checks to reduce abuse of enumeration endpoints.

🔴 apps/app/src/app/(app)/[orgId]/people/all/actions/sendInvitationEmail.ts (HIGH Risk)

# Issue Risk Level
1 Missing validation for email, organizationId, and roles before DB usage. HIGH
2 No role whitelist—caller can set arbitrary roles (possible privilege escalation). HIGH
3 No check for existing member or existing invitation before creation. HIGH
4 Invitation IDs may be guessable if underlying IDs are predictable. HIGH
5 Errors logged to console may expose sensitive data in logs. HIGH

Recommendations:

  1. Validate and sanitize inputs server-side before any DB usage: ensure email is a valid email (normalize to lowercase), organizationId matches expected format (e.g., UUID), and roles is a non-empty array of allowed values.
  2. Enforce a server-side role whitelist and disallow assignment of privileged roles like 'owner' unless explicitly authorized. Map incoming roles to allowed internal role values rather than storing raw input.
  3. Check for existing membership and existing pending invitations before creating a new invitation. Return a safe, idempotent response (e.g., success with note that invite already exists) to avoid duplicate records and information leakage.
  4. Use an unguessable invitation token for links (e.g., UUID v4 or cryptographically secure random token) stored as a separate column (token) instead of exposing the primary invitation id in the URL. Keep the primary key opaque in endpoints.
  5. Avoid logging raw errors to console in production. Redact or sanitize sensitive fields before logging, and use structured logging with appropriate log levels. Consider capturing stack traces only to secure error reporting systems accessible to developers, not standard console output.

🟡 apps/app/src/app/(app)/[orgId]/people/all/components/InviteMembersModal.tsx (MEDIUM Risk)

# Issue Risk Level
1 User enumeration via checkMemberStatus revealing account existence MEDIUM
2 Potential mass-email/spam abuse via client-triggered invite flows MEDIUM
3 Internal errors logged/stored (error.message) may leak sensitive info MEDIUM
4 CSV upload may allow CSV/formula injection when opened in spreadsheets MEDIUM
5 Inconsistent role type sent (string or array) could cause API misuse MEDIUM
6 No rate limiting for invite actions may enable abuse MEDIUM

Recommendations:

  1. Move sensitive checks and invitation actions to a trusted server-side endpoint. Do not call checkMemberStatus or authClient.organization.inviteMember directly from unprivileged client code. Perform member existence checks and invite sending on the server and return only generic success/failure results to the client.
  2. Prevent user enumeration: make server responses identical for existing/non-existing accounts (timing and content). If you must indicate state, require elevated privileges and do checks server-side.
  3. Implement server-side rate limiting, quotas, and abuse detection for invite endpoints (per IP, per authenticated user, and per organization). Consider exponential backoff, CAPTCHAs for bulk invites, and monitoring/alerting on abnormal invite volumes.
  4. Avoid exposing internal error messages to end users. Log full error details server-side and return generic messages to the client. Remove or avoid persisting error.message in client-visible state or UI.
  5. Sanitize CSV contents before any downstream use/export. To mitigate CSV/formula injection, escape leading characters (=, +, -, @) or prefix values with a safe character when producing CSV exports or when writing back to spreadsheets. Validate and normalize inputs server-side as well.
  6. Standardize the invite API contract so role is a consistent type (e.g., always an array). Validate types server-side and reject malformed requests. If the upstream API supports both, wrap client calls in a server endpoint that normalizes/validates the payload.
  7. Validate all inputs server-side (emails, roles) even if validated client-side. Treat client validation as UX only.
  8. Consider limiting client-side bulk operations (e.g., maximum rows in CSV) and require server-side authorization checks for bulk invites.

🟡 apps/app/src/app/(app)/[orgId]/tasks/components/TaskList.tsx (MEDIUM Risk)

# Issue Risk Level
1 Unsanitized orgId/view sent to updateTaskViewPreference (SQL injection risk) MEDIUM
2 Client-side role checks for assignee eligibility can be bypassed MEDIUM
3 Query params (status, assignee, create-task) used without validation MEDIUM

Recommendations:

  1. Treat orgId and view as untrusted. Validate and sanitize them on the server before using in any DB queries or building SQL. Use strong type checks (e.g., ensure orgId matches UUID/expected pattern and view is one of allowed enum values).
  2. Ensure backend action handling updateTaskViewPreference uses parameterized queries / ORM parameter binding (no string concatenation into SQL). Validate inputs server-side and enforce authorization before persisting preference.
  3. Do not rely on client-side role checks for authorization. Enforce all authorization (who can be assigned, who can change preferences, who can create tasks) on the server.
  4. Validate and type-check query parameters (status, assignee, create-task) server-side before using them. Use schema validators (e.g., zod, yup) to coerce and validate types and allowed values.
  5. Log and rate-limit preference updates and other mutating endpoints to detect abuse and reduce risk of enumeration/brute-force attacks.
  6. Apply defense-in-depth: use CSRF protections for state-changing endpoints, require auth tokens, and return minimal error information to callers.

🟡 apps/app/src/app/(app)/[orgId]/tasks/page.tsx (MEDIUM Risk)

# Issue Risk Level
1 Members query includes user data (possible sensitive data leak) MEDIUM
2 No explicit authorization check before returning org data MEDIUM
3 Session retrieved from headers; header spoofing may affect auth MEDIUM

Recommendations:

  1. Limit the fields returned for member.user (select only needed fields, e.g., id, name) instead of include: true to avoid exposing emails/password hashes/PII.
  2. Add an explicit authorization/permission check after obtaining the session to ensure the caller is allowed to view the requested organization's data (e.g., verify session.userId is a member of the org and has the required role).
  3. Ensure auth.api.getSession fully validates tokens (signatures/expiry) and use secure cookie attributes (HttpOnly, Secure, SameSite) or validated Authorization headers. Do not assume headers cannot be spoofed—validate the session token server-side.
  4. Sanitize and validate any route parameter before using it in security-relevant contexts (e.g., when used to set cookie names, filesystem paths, or as part of queries). Even if reading a cookie key using orgId is low-risk, avoid using unvalidated input when constructing keys that might later be used in storage or log entries.
  5. When returning organization data, consider returning only the minimal data required by the client and auditing/logging access to sensitive queries.
  6. Add server-side logging and rate limiting around data-fetching endpoints to detect abuse and brute-force attempts against session tokens or org identifiers.

💡 Recommendations

View 3 recommendation(s)
  1. Upgrade affected npm packages: bump xlsx (0.18.5) to a patched release addressing GHSA-4r6h-8v6p-xvw6 and GHSA-5pgg-2g8v-p4x9, and upgrade ai to >= 5.0.52 (fixes GHSA-rwvc-j5jr-mgvh).
  2. Sanitize/validate orgId and view before use (apps/app/src/actions/tasks.ts and TaskList.tsx): enforce a strict allowlist (e.g., UUID or /^[A-Za-z0-9_-]{1,64}$/), encode cookie names/values instead of inserting raw user input, and use parameterized queries / ORM bindings for updateTaskViewPreference to prevent SQL injection.
  3. Mitigate CSV/formula injection and sensitive logging (apps/app/src/app/(app)/[orgId]/people/all/components/InviteMembersModal.tsx and sendInvitationEmail.ts): escape leading characters (=,+,-,@) in CSV cells, add server-side validation/normalization for emails and roles, and stop returning or logging raw error strings to clients/logs.

Powered by Comp AI - AI that handles compliance for you. Reviewed Nov 26, 2025

@vercel
Copy link

vercel bot commented Nov 26, 2025

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

Project Deployment Preview Comments Updated (UTC)
app (staging) Ready Ready Preview Comment Nov 26, 2025 7:46pm
portal (staging) Ready Ready Preview Comment Nov 26, 2025 7:46pm

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ carhartlewis
❌ github-actions[bot]
You have signed the CLA already but the status is still pending? Let us recheck it.

@Marfuen Marfuen merged commit d49746e into release Nov 26, 2025
11 of 13 checks passed
@claudfuen
Copy link
Contributor

🎉 This PR is included in version 1.66.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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.

5 participants