Skip to content

Conversation

@github-actions
Copy link
Contributor

This is an automated pull request to merge mariano/sales-improvements into dev.
It was created by the [Auto Pull Request] action.

@vercel
Copy link

vercel bot commented Nov 18, 2025

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

Project Deployment Preview Comments Updated (UTC)
app Ready Ready Preview Comment Nov 18, 2025 11:10pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
portal Skipped Skipped Nov 18, 2025 11:10pm

@comp-ai-code-review
Copy link

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

🔒 Comp AI - Security Review

🔴 Risk Level: HIGH

OSV: xlsx@0.18.5 -> Prototype Pollution & ReDoS; ai@5.0.0 -> filetype whitelist bypass (fix in 5.0.52). Code: unvalidated route/orgId params used in DB/URLs and revalidation secret exposure.


📦 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 19 file(s) with issues

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

# Issue Risk Level
1 Using metadata ids as object keys allows prototype pollution MEDIUM
2 No type validation for numeric/boolean metadata fields MEDIUM
3 Metadata-driven UI trusts remote data without server-side validation MEDIUM
4 Derived orgId/pathname not validated before use MEDIUM

Recommendations:

  1. Avoid using untrusted strings directly as plain object keys. Create maps with Object.create(null) (e.g., const vendorsStatus = Object.create(null)) and explicitly validate IDs (allow only a safe charset such as /^[A-Za-z0-9_-]+$/). Reject or normalize keys like 'proto', 'constructor', 'prototype'.
  2. Perform explicit type validation/coercion for numeric/boolean metadata fields instead of relying on || fallbacks. Example: const vendorsTotal = Number(meta.vendorsTotal); if (Number.isNaN(vendorsTotal) || vendorsTotal < 0) vendorsTotal = 0. For booleans, coerce via meta.flag === true or meta.flag === 'true'.
  3. Treat run.metadata as untrusted input. Enforce schema validation server-side (or at the API boundary) and only surface vetted fields to the client. Use a runtime validator (Zod/Joi/ajv) on the producer side and strip unexpected keys before sending to clients.
  4. Validate and normalize orgId/pathname-derived values before using them in links or logic. Restrict to expected formats (e.g., alphanumeric + allowed punctuation) and handle missing/invalid values safely. When constructing hrefs, ensure the path cannot be turned into an unintended scheme or absolute external URL.

🟡 apps/app/src/app/(app)/[orgId]/integrations/actions/get-relevant-tasks.ts (MEDIUM Risk)

# Issue Risk Level
1 No input validation for integrationName, integrationDescription, or taskTemplates MEDIUM
2 Parsed error.text JSON returned without schema validation MEDIUM
3 Attacker-controlled model/error output used directly in responses MEDIUM
4 Potential log injection by logging raw error or error.text MEDIUM

Recommendations:

  1. Validate all function inputs (integrationName, integrationDescription, taskTemplates) using a schema (e.g., zod). Enforce types, maximum lengths, allowed characters, and array size limits before using values in prompts or logs.
  2. When recovering data from error.text, run the parsed object through RelevantTasksSchema.parse()/safeParse() before returning. Reject or sanitize any output that doesn't fully match the schema.
  3. Treat model output as untrusted. After generateObject or any model/error JSON, validate and sanitize every field (taskTemplateId, taskName, reason, prompt). Normalize/escape or drop unexpected fields and enforce length limits.
  4. Avoid logging raw user/model-provided strings. Sanitize or escape control characters (newlines, carriage returns, terminal escape sequences) and truncate long values before writing to logs.
  5. Implement defensive defaults: if validation/sanitization fails, return an empty array or a safe error response rather than untrusted data recovered from an error payload.
  6. Consider provenance/authority controls: add confidence checks, sampling, or human review for high-impact tasks produced by models before triggering downstream actions.

🟡 apps/app/src/app/(app)/[orgId]/policies/all/components/policies-table.tsx (MEDIUM Risk)

# Issue Risk Level
1 Client calls server-only getLogsForPolicy directly MEDIUM
2 No auth/permission check before subscribing to onboarding run MEDIUM
3 orgId from URL used without validation in row URL MEDIUM
4 Unvalidated run.metadata used to derive policy statuses/progress MEDIUM
5 Policy logs used to generate PDFs without sanitization MEDIUM

Recommendations:

  1. Call getLogsForPolicy via an authenticated server API endpoint
  2. Validate and sanitize orgId from useParams before use
  3. Enforce auth/authorization checks before subscribing or fetching logs
  4. Validate run.metadata types and value ranges before trusting them
  5. Sanitize and escape policy logs before including them in generated PDFs

🔴 apps/app/src/app/(app)/[orgId]/policies/all/page.tsx (HIGH Risk)

# Issue Risk Level
1 No authorization/ownership check before DB queries with orgId HIGH
2 User-controlled searchParams passed to getPolicies (possible injection) HIGH
3 orgId used directly in DB where clause without explicit validation HIGH

Recommendations:

  1. Enforce authentication and authorization: verify the current user is authenticated and is authorized to access orgId before any DB call that uses orgId (e.g., check membership/roles for the org in middleware or the route handler).
  2. Validate and canonicalize route parameters: explicitly validate orgId (type/format, e.g., UUID or numeric ID) before using it in DB queries to avoid unexpected types.
  3. Harden search parameter handling: whitelist allowed search/filter/sort fields and values. Ensure searchParamsCache.parse and getValidFilters perform strict validation (types, allowed operators, allowed fields) and reject or normalize anything unexpected.
  4. Audit getPolicies implementation: confirm it uses parameterized ORM queries (no string concatenation or raw SQL built from user input). If it uses raw queries, switch to parameterized queries or sanitize/escape all inputs strictly.
  5. Ensure DB layer uses parameterized queries/ORM: using an ORM where the where clause is an object (as shown) is typically safe, but verify db.onboarding and getPolicies do not pass user input into raw SQL or template strings.
  6. Add logging and tests: add unit/integration tests for malicious search inputs and for orgId access control, and log unauthorized access attempts for monitoring.
  7. Apply least privilege and rate limiting: ensure endpoints enforce least privilege for data access and apply rate limiting to reduce blast radius of abuse.

🟡 apps/app/src/app/(app)/[orgId]/risk/(overview)/RisksTable.tsx (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated URL params passed to getRisksAction (client->server) MEDIUM
2 Frequent 1s polling could enable DoS or excessive resource use MEDIUM

Recommendations:

  1. Enforce server-side runtime validation of all incoming search parameters before using them in business logic. Although you have a searchParams parser type (GetRiskSchema) in data/validations.ts, TypeScript types are compile-time only — call a runtime parser/validator (e.g., the nuqs/server parser or zod) at the start of getRisksAction/getRisks to ensure inputs are well-formed.
  2. Harden the getRisks path to explicitly validate/normalize fields that become keys (e.g., sort[].id, joinOperator) to avoid unexpected behavior if malformed data is received. Convert/whitelist sort ids and joinOperator values at runtime rather than relying solely on client-side parsing.
  3. Replace or augment 1s polling with a less aggressive strategy: increase interval, use exponential backoff, use server-sent events / WebSockets for push updates, or add client-side debounce/throttling. On the server side, implement rate limiting for the endpoint to avoid resource exhaustion from many clients polling.
  4. Continue to rely on the ORM's parameterized APIs for query construction (Prisma is used here), but still validate inputs for correctness (types/allowed fields). Do not interpolate raw user input into raw SQL.
  5. If item names/content might ever be inserted as HTML, ensure proper HTML escaping or use a sanitizer. In the current code paths shown, item.name is placed as plain text into React components (React escapes by default), so avoid using dangerouslySetInnerHTML unless the content is sanitized.

🟡 apps/app/src/app/(app)/[orgId]/risk/(overview)/actions/get-risks-action.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated user input forwarded to getRisks MEDIUM

Recommendations:

  1. Enforce runtime validation of the input inside getRisksAction (or immediately at its callsite) using the provided parsers/zod schema (e.g., call searchParamsCache.parse or an equivalent runtime check) before forwarding to getRisks.
  2. Add strict limits and type coercion on inputs (page, perPage, title length, filters size, etc.) to avoid large/abusive payloads or unexpected types.
  3. If getRisksAction is exposed as an API endpoint, ensure the endpoint caller cannot bypass the parsers — perform server-side parsing/validation rather than relying solely on TypeScript types.
  4. Add explicit defensive checks for joinOperator and filter contents before using them to build the Prisma where clause (although validations.ts already constrains joinOperator, validate at runtime if input may come from untrusted sources).
  5. Audit the data layer for any usage of raw queries or exec/eval; prefer Prisma findMany/count (parameterized) as used in getRisks and avoid db.$queryRaw or string concatenation with user input.

🟡 apps/app/src/app/(app)/[orgId]/risk/(overview)/components/table/RiskColumns.tsx (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated orgId/risk.id used in Link href — may form external/protocol-relative URL MEDIUM
2 User-controlled assignee.image used as img src; may leak IP/tracking MEDIUM

Recommendations:

  1. Validate and whitelist orgId and risk.id on both client and server (allow only expected characters, e.g. alphanumeric, dashes/underscores). Reject values with leading '//' or schemes (http:, https:, data:, javascript:).
  2. When building internal links, encode path segments (e.g., encodeURIComponent(orgId) and encodeURIComponent(risk.id)) or use Next.js Link with pathname/query object ({ pathname: '/[orgId]/risk/[id]', query: { orgId, id } }) so segments are not interpreted as a protocol/host.
  3. On the server, canonicalize and re-validate IDs used in routing to ensure malicious input cannot produce an external URL or path traversal.
  4. Restrict/validate assignee.image URLs: allowlist trusted domains and enforce http(s) scheme. Reject protocol-relative ('//') and data/javscript URIs.
  5. Prefer proxying external images through a server-side/image CDN (or use Next.js Image with remotePatterns) so client browsers don't directly contact arbitrary third-party hosts, preventing IP/tracking leaks.
  6. If direct external images are required, set appropriate attributes (e.g., referrerPolicy='no-referrer') and use Content Security Policy (CSP) to limit allowed image sources — but note referrerPolicy does not prevent IP-address exposure to third parties.
  7. Validate and sanitize all server-provided user fields (name, email, image) before rendering in the UI. Log and monitor any rejections.

🟢 apps/app/src/app/(app)/[orgId]/risk/(overview)/hooks/use-onboarding-status.ts (LOW Risk)

# Issue Risk Level
1 Unsanitized external run.metadata used directly LOW
2 Unvalidated item.id used to build metadata keys LOW

Recommendations:

  1. Validate the shape and types of run.metadata before using it. Use a runtime schema validator (e.g., Zod, io-ts) or explicit type checks to assert expected fields (e.g., ${itemType}Info is an array of objects with string id and name, ${itemType}Total and ${itemType}Completed are numbers).
  2. Normalize and sanitize values taken from metadata. For example, coerce numeric fields with Number() and fall back to 0 on NaN, and ensure status values are one of the allowlisted strings.
  3. Allowlist item.id values used to build dynamic keys. Restrict characters and length (e.g., /^[A-Za-z0-9_-]{1,64}$/) and reject or canonicalize any id that does not match expectations.
  4. Avoid using external data to construct critical keys or identifiers without validation. If dynamic keys are required, map validated item ids to safe internal keys (e.g., use a validated id or index-based mapping).
  5. When rendering UI with values from metadata, ensure proper escaping/encoding in the UI layer and avoid injecting metadata into raw HTML.
  6. Return safe defaults when metadata is missing or has unexpected shapes (already partly implemented — ensure all code paths are covered). Add unit tests that exercise malformed metadata shapes.

🟡 apps/app/src/app/(app)/[orgId]/risk/[riskId]/actions/regenerate-risk-mitigation.ts (MEDIUM Risk)

# Issue Risk Level
1 Auth/permission bypass: any session with activeOrganizationId can trigger regeneration MEDIUM
2 Weak validation: riskId only checked non-empty; no format/sanitization MEDIUM
3 Unvalidated inputs forwarded to background job/db may cause downstream injection or misuse MEDIUM

Recommendations:

  1. Enforce org-level RBAC: explicitly verify the authenticated user has permission to regenerate mitigations for the given organization (e.g., check membership + role/permission). Do not rely solely on presence of session.activeOrganizationId.
  2. Verify resource ownership: when operating on a riskId, confirm the risk exists and belongs to session.activeOrganizationId (db lookup such as db.risk.findUnique({ where: { id: riskId, organizationId } })).
  3. Tighten input validation: replace z.string().min(1) with a stricter schema (e.g., z.string().uuid() or a pattern / length check) to ensure riskId conforms to expected format.
  4. Validate and sanitize before enqueueing jobs: validate riskId and other fields again in the background job handler, and avoid trusting the client or a single server-side check.
  5. Ensure downstream code uses parameterized queries/ORM safely and does not interpolate riskId into raw SQL/commands. Review generate-risk-mitigation job for any uses of riskId in exec/eval/raw SQL.
  6. Verify chosen author is explicitly eligible and belongs to the same organization and has required permissions before using author.id.
  7. Add audit logging and rate limiting on this action, and add monitoring/alerts for abnormal volumes or repeated failures to detect abuse.

🟡 apps/app/src/app/(app)/[orgId]/tasks/[taskId]/automation/[automationId]/actions/generate-suggestions.ts (MEDIUM Risk)

# Issue Risk Level
1 Unsanitized organizationId used directly in DB queries MEDIUM
2 No runtime validation of taskDescription before building AI prompt MEDIUM
3 Blind JSON.parse of error.text without schema validation MEDIUM
4 AI-generated suggestions returned without output sanitization MEDIUM

Recommendations:

  1. Validate and sanitize organizationId before DB operations: assert type/format (e.g., UUID or numeric), reject or canonicalize unexpected values, and if raw SQL is ever used prefer parameterized queries. Even with ORMs, validate inputs at the boundary.
  2. Add runtime validation for taskDescription: enforce max length, allowed character set or normalized encoding, and reject or truncate overly large inputs before building prompts to avoid prompt- and resource-exhaustion attacks.
  3. Validate any parsed error payloads with a schema validator (e.g., zod) before trusting fields from JSON.parse(error.text). Wrap JSON.parse in try/catch and run the result through the same SuggestionsSchema used for normal AI output.
  4. Sanitize AI-generated content before returning or rendering: enforce the SuggestionsSchema on outputs, escape or strip HTML/JS to prevent XSS when displayed in a browser, and validate vendorWebsite as a safe URL format before including it.
  5. Enforce prompt length caps, rate limits, and token limits for AI calls to reduce abuse and DoS risk; log and monitor AI usage and unexpected responses.
  6. Defensive logging and alerting: record anomalous inputs and recovered-parsed payloads (without leaking secrets) and create alerts for repeated parse-recoveries or malformed AI outputs.

🟡 apps/app/src/app/(app)/[orgId]/vendors/(overview)/actions/get-vendors-action.ts (MEDIUM Risk)

# Issue Risk Level
1 No runtime validation for 'input' (TypeScript types only) MEDIUM
2 Input passed directly to getVendors (possible SQL injection) MEDIUM
3 Authorization relies only on presence of activeOrganizationId MEDIUM
4 Potential sensitive data exposure from raw vendor response MEDIUM

Recommendations:

  1. Add runtime schema validation for input (e.g., Zod/Joi) at the start of getVendorsAction to enforce required fields, types, lengths and reject unexpected properties.
  2. Audit getVendors implementation to ensure it uses parameterized queries / prepared statements or an ORM that auto-parameterizes queries. Never interpolate raw input into SQL strings.
  3. Perform explicit authorization checks: verify the session user is a member of and authorized for session.session.activeOrganizationId (check membership/roles/permissions) before querying or returning data.
  4. Map and sanitize vendor output server-side: return a DTO that includes only non-sensitive fields (avoid returning raw DB rows). Remove or redact fields like SSNs, internal notes, credentials, tokens, etc.
  5. Implement centralized error handling and logging that records errors for ops but returns generic error messages to clients (no stack traces or raw DB errors).
  6. Add unit/integration tests and input-fuzzing for getVendors to ensure edge cases and injection attempts are handled safely.

🟡 apps/app/src/app/(app)/[orgId]/vendors/(overview)/components/VendorsTable.tsx (MEDIUM Risk)

# Issue Risk Level
1 User-controlled URL params forwarded to getVendorsAction MEDIUM
2 Potential injection if server uses params in DB queries MEDIUM
3 Filters/sort objects sent as JSON may carry malicious input MEDIUM
4 No explicit server-side auth check for orgId before fetching MEDIUM
5 1s polling while onboarding active could enable resource exhaustion MEDIUM

Recommendations:

  1. Perform strict server-side validation and sanitization of all incoming parameters (page, perPage, name, status, department, assigneeId, sort, filters, joinOperator). Treat client-side parsing as UX convenience only.
  2. Use parameterized queries / ORM bindings for all DB access. Never interpolate raw request values into SQL or query strings.
  3. Validate and constrain sort and filter schemas server-side (allow-list fields, types, lengths). Parse JSON payloads safely and reject unexpected structures.
  4. Enforce server-side authorization: verify session and that the requesting user is a member of orgId and allowed to view the requested organization data before returning vendor data.
  5. Reduce polling impact: increase interval, add exponential backoff, only poll when UI is visible/focused, or use server push (webhooks / websockets / SSE). Implement rate-limiting on the API to guard against abusive polling.
  6. Log and monitor unusual query patterns or high-frequency calls to detect abuse or automated scraping attempts.

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

# Issue Risk Level
1 Missing authorization check for orgId before DB/data access MEDIUM
2 Unvalidated orgId used directly in DB queries MEDIUM
3 Potential SQL injection via orgId in getVendors/getAssignees if queries are not parameterized MEDIUM
4 Information disclosure: empty/default view reveals org state MEDIUM

Recommendations:

  1. Enforce auth/authorization to ensure user can access orgId resources
  2. Validate and sanitize orgId (UUID pattern) before use
  3. Use parameterized ORM queries to prevent SQL injection
  4. Limit org state exposure; avoid revealing empty data to unauthenticated users
  5. Audit getVendors/getAssignees for unsafe query construction

🟡 apps/app/src/components/data-table/data-table.tsx (MEDIUM Risk)

# Issue Risk Level
1 Unencoded row id used in router.push — URL/path injection risk MEDIUM
2 rowClickBasePath may allow navigation to external URLs (open redirect) MEDIUM
3 Arbitrary column header/cell renderers may output unsafe HTML (XSS) MEDIUM

Recommendations:

  1. Encode path segments: call encodeURIComponent(getRowId(row)) before appending to the path or otherwise ensure the id is a safe path segment. Example: const id = encodeURIComponent(getRowId(row)); router.push(${safeBase}/${id});
  2. Validate/allowlist rowClickBasePath to ensure it is an internal path. Require it to start with '/' and reject values that contain a scheme (e.g., 'http:','https:'), hostname, or leading '//' which would form an absolute/external URL. Example check: if (!rowClickBasePath.startsWith('/') || /(^//|^[a-zA-Z][a-zA-Z0-9+.-]*:)/.test(rowClickBasePath)) { throw new Error('invalid base path') }
  3. Use structured navigation APIs where possible instead of naive string concatenation. For Next.js you can push with a pathname/query object (or use next/link with href objects) so path segments and query values are managed rather than concatenated: router.push({ pathname: ${rowClickBasePath}/[id], query: { id } }) or a helper that safely joins path segments.
  4. Whitelist/validate getRowId outputs: if IDs are expected to be alphanumeric (or a specific format), enforce that (e.g., /^[A-Za-z0-9-_]+$/). Reject or sanitize unexpected characters.
  5. Prevent open redirects for user-provided base paths: accept only known safe values (enum) or ensure base is generated server-side / by trusted code rather than user input.
  6. For renderer/XSS concerns: avoid using dangerouslySetInnerHTML in your column header/cell renderers. If you must render HTML from data, sanitize it server- or client-side with a proven library (e.g., DOMPurify) and escape content by default. Treat column renderers as trusted code: if you allow column definitions to render user-provided strings as HTML, explicitly sanitize those strings before rendering.
  7. Add tests validating navigation inputs (invalid base path, ids with special chars) and renderer outputs (ensure user content is escaped or sanitized).

🟡 apps/app/src/env.mjs (MEDIUM Risk)

# Issue Risk Level
1 Env validation can be skipped by CI or SKIP_ENV_VALIDATION MEDIUM
2 NEXT_PUBLIC_PORTAL_URL exposed to client-side bundles MEDIUM
3 Client NEXT_PUBLIC_* keys may leak sensitive data if misused MEDIUM
4 Many sensitive vars are optional, allowing missing secrets MEDIUM
5 Sensitive tokens mapped in runtimeEnv may be exposed at runtime MEDIUM

Recommendations:

  1. Remove NEXT_PUBLIC_* prefix from any environment variables that must remain server-only (e.g., NEXT_PUBLIC_PORTAL_URL) so they are not bundled into client code.
  2. Make critical server secrets required in the schema (use z.string().min(1) or z.string() without .optional()) so the app fails startup when secrets are missing.
  3. Avoid automatically skipping env validation in CI. Remove or guard skipValidation: !!process.env.CI || !!process.env.SKIP_ENV_VALIDATION so CI builds validate envs; only allow SKIP_ENV_VALIDATION under a deliberate, auditable override.
  4. Audit all NEXT_PUBLIC_* entries and ensure no secret (API keys, tokens, DB connection strings) is given a NEXT_PUBLIC_ name. Move any secret usages to server-only code paths.
  5. Limit runtime exposure: only map server-only secrets into server contexts. Where client code needs non-sensitive endpoints, provide them via server APIs rather than exposing raw secrets.
  6. If any secrets may have been exposed to clients or CI, rotate those secrets and review access logs.

🟡 apps/app/src/jobs/tasks/onboarding/generate-full-policies.ts (MEDIUM Risk)

# Issue Risk Level
1 Missing validation of payload.organizationId before DB queries MEDIUM
2 Potential SQL injection via unvalidated organizationId in ORM queries MEDIUM
3 No authorization check for access to organization data MEDIUM
4 Logging raw error.message may leak sensitive info MEDIUM

Recommendations:

  1. Validate and sanitize payload.organizationId (format and type)
  2. Enforce authorization checks for org access before DB operations
  3. Avoid logging raw error messages; redact sensitive data
  4. Use input schema validation (e.g., Zod/Joi) for task payloads
  5. Restrict task triggers to authenticated/internal sources

🟡 apps/app/src/jobs/tasks/onboarding/generate-vendor-mitigation.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated authorId used to set vendor assignee MEDIUM
2 Task payload not validated before DB queries/updates MEDIUM
3 Revalidation secret sent to URL built from NEXT_PUBLIC_BETTER_AUTH_URL (public env var) MEDIUM

Recommendations:

  1. Validate and authorize authorId before using it to set vendor.assigneeId — ensure the author exists, belongs to the organization, and has permission to be assigned. Prefer using server-resolved authors (e.g., findCommentAuthor) rather than trusting an externally provided authorId.
  2. Validate and sanitize task payload fields (organizationId, vendorId, authorId) before database access. Check types and existence; confirm the vendor belongs to the organization and that the caller is authorized to trigger the operation.
  3. Avoid constructing internal API endpoints from publicly-named env vars (NEXT_PUBLIC_*). Use server-only environment variables for internal service URLs (e.g., BETTER_AUTH_URL) that are not exposed to client builds.
  4. Do not POST sensitive secrets to endpoints that could be controlled externally. Keep revalidation secrets confined to server-side components and call internal endpoints directly or use a signed, short-lived token pattern that limits scope.
  5. Restrict who/what can trigger these tasks (task queue authorization). If external triggers are required, require authentication/authorization and validate payloads server-side before performing DB updates.
  6. Add logging and alerting for unexpected authorId/assignee changes and for failed/suspicious revalidation attempts.

🟡 apps/app/src/jobs/tasks/onboarding/onboard-organization-helpers.ts (MEDIUM Risk)

# Issue Risk Level
1 No validation of organizationId before database queries MEDIUM
2 Vendor object fields used in DB without validation/sanitization MEDIUM
3 AI-generated comment content stored without sanitization (stored XSS) MEDIUM
4 Revalidation secret sent in request body could be exposed MEDIUM
5 Logging response data and full error objects may leak secrets/PII MEDIUM

Recommendations:

  1. Validate and/or assert organizationId format (e.g., UUID checks) at the function boundary. Reject or canonicalize unexpected shapes before calling DB functions.
  2. Validate and normalize vendor fields before DB insertion: enforce length limits, allowlist categories, validate URLs, and reject or canonicalize unexpected characters.
  3. Sanitize or escape any AI-generated text before storing/serving (HTML-escape when rendering in UI). Consider storing raw and a sanitized copy, and treat AI output as untrusted.
  4. Avoid embedding sensitive secrets in request bodies where they may be logged or leaked. Use short-lived tokens, signed headers, or mTLS for internal service-to-service revalidation. If a secret must be sent, ensure transmission over TLS and minimize logging of the request/response.
  5. Reduce logging of whole response bodies and exception objects. Redact sensitive keys (secrets, tokens, PII) before logging. Use structured logs with fields explicitly marked as sensitive when necessary.
  6. Although BETTER_AUTH_URL is an environment variable (not user-controlled), validate and freeze acceptable revalidation endpoints (allowlist) and ensure it uses https. Treat environment values as configuration that should be controlled by the operator — document and enforce that it must not be user-controlled.

🟡 apps/app/src/jobs/tasks/onboarding/onboard-organization.ts (MEDIUM Risk)

# Issue Risk Level
1 Missing validation of payload.organizationId before DB use MEDIUM
2 questionsAndAnswers passed to helpers without input validation MEDIUM
3 Metadata entries may expose unsanitized user input to UI (XSS) MEDIUM
4 Revalidation secret sent in request body could be exposed MEDIUM
5 Unconditional role update to 'owner,employee' may escalate privileges MEDIUM
6 Logging orgId and error messages may leak sensitive info to logs MEDIUM

Recommendations:

  1. Validate and allowlist organizationId before using in DB queries (e.g., require UUID format or lookup in a trusted table). Fail fast if invalid.
  2. Validate and sanitize questionsAndAnswers and any other user-provided context before passing to helper functions and before storing or acting on values. Use schema validation (zod/joi) and strict typing at boundaries.
  3. Escape or sanitize any values placed into metadata that will be rendered in the UI (vendor names, policy names, organization.name). Treat metadata as untrusted and HTML-encode/escape on render, or sanitize on set.
  4. Avoid sending secrets in request bodies when possible; send revalidation secrets in an authorization header and ensure the revalidation endpoint is on an allowlisted, HTTPS-only domain. Validate NEXT_PUBLIC_BETTER_AUTH_URL against a known allowlist and require HTTPS.
  5. Before updating roles, check current role(s) and only add the minimal necessary privilege. Consider using an explicit role-add operation (e.g., add 'employee' if not present) and audit/log an administrative approval for privilege changes.
  6. Redact or avoid logging sensitive values (full organization IDs, secrets, PII). Use structured logs with controlled access and ensure logs are protected (retention, ACLs).

💡 Recommendations

View 3 recommendation(s)
  1. Remediate OSV findings: upgrade ai to >=5.0.52 and update or replace xlsx (0.18.5) with a patched SheetJS release; re-run dependency scan and pin updated versions in package.json/lockfile.
  2. Sanitize and validate runtime inputs before use: add a runtime schema (e.g., Zod) to validate orgId, riskId, task/vendor IDs and all search/filter params (e.g., require UUID or strict regex) before any DB calls or constructing hrefs; use encodeURIComponent when building path segments (router.push or Link) to prevent path/URL injection.
  3. Remove secrets from client-exposed flows and stop sending revalidation secrets in request bodies: treat BETTER_AUTH_URL and revalidation secret as server-only, call the revalidation endpoint from server-side code and send the secret in an Authorization header (not in a public NEXT_PUBLIC_* var or request body) to avoid accidental exposure.

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

@vercel vercel bot temporarily deployed to Preview – portal November 18, 2025 23:07 Inactive
@Marfuen Marfuen merged commit 6c6f188 into main Nov 18, 2025
8 of 9 checks passed
@Marfuen Marfuen deleted the mariano/sales-improvements branch November 18, 2025 23:08
@claudfuen
Copy link
Contributor

🎉 This PR is included in version 1.60.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.

3 participants