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.

github-actions bot and others added 2 commits November 25, 2025 22:31
* feat(api): add AI chat endpoint for policy editing assistance, initial draft for ai policy edits

* fix: type error

* feat(policy-editor): integrate AI-assisted policy editing with markdown support

* refactor(api): streamline POST function and enhance markdown guidelines

* refactor(policy-editor): improve policy details layout and diff viewer integration

* refactor(policy-editor): simplify policy details component and enhance AI assistant integration

* refactor(policy-editor): remove unused AI assistant logic and simplify component structure

* feat(ui): add new components to package.json for diff viewer and AI elements

* chore: update lockfile

* refactor(tsconfig): reorganize compiler options and update paths

* fix(policies): resolve infinite loop in policy AI assistant

* fix(api): update policy editing assistant instructions and tool usage

---------

Co-authored-by: Daniel Fu <itsnotaka@gmail.com>
Co-authored-by: Amp <amp@ampcode.com>
@comp-ai-code-review
Copy link

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

Comp AI - Code Vulnerability Scan

Analysis in progress...

Reviewing 30 file(s). This may take a few moments.


Powered by Comp AI - AI that handles compliance for you | Reviewed Nov 26, 2025, 04:58 PM

@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 6:58pm
portal (staging) Ready Ready Preview Comment Nov 26, 2025 6:58pm

@CLAassistant
Copy link

CLAassistant commented Nov 26, 2025

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.

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
@comp-ai-code-review
Copy link

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

🔒 Comp AI - Security Review

🔴 Risk Level: HIGH

OSV: xlsx@0.18.5 has two HIGH advisories (GHSA-4r6h-8v6p-xvw6, GHSA-5pgg-2g8v-p4x9); ai@5.0.0 has a LOW advisory (GHSA-rwvc-j5jr-mgvh). .env.example contains hardcoded DB creds; export endpoint allows spreadsheet formula injection.


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

🟡 SELF_HOSTING.md (MEDIUM Risk)

# Issue Risk Level
1 .env example contains DATABASE_URL with credentials MEDIUM
2 Using env_file (.env) risks committing secrets to VCS MEDIUM
3 NEXT_PUBLIC_* variables can leak sensitive config to clients MEDIUM
4 Required API keys (RESEND_API_KEY, TRIGGER_SECRET_KEY) in env MEDIUM
5 AWS S3 creds stored in env (APP_AWS_*) can be exposed MEDIUM
6 OPENAI_API_KEY in env may be leaked and abused MEDIUM
7 UPSTASH_REDIS_REST_TOKEN in env can be stolen and misused MEDIUM
8 TRIGGER_SECRET_KEY exposure can allow workflow hijacking MEDIUM
9 Docker-compose exposes ports 3000 and 3002 to host network MEDIUM
10 Example base URLs use http (non-TLS) which risks interception MEDIUM
11 No Docker secrets or secret management configured MEDIUM
12 Prisma migrations require DB alter privileges; risky on prod MEDIUM
13 Seeder performs upserts with DB access; could modify data MEDIUM
14 Healthchecks reveal local endpoints if publicly reachable MEDIUM
15 No guidance to rotate or revoke leaked credentials MEDIUM

Recommendations:

  1. Never commit real .env files. Keep only a .env.example with placeholders and add .env to .gitignore.
  2. Use a dedicated secrets manager (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, Azure Key Vault) or Docker secrets for production; do not rely on plain .env files in repo.
  3. Do not put secrets in NEXT_PUBLIC_* variables (they are exposed to client). Move any secret or sensitive keys to server-only env vars.
  4. Use least-privilege credentials for DB and S3 (separate users/roles for runtime app, migrations, and seeding). Consider creating a migration user with limited lifetime or run migrations from a controlled CI/CD job.
  5. Require TLS (https) for public URLs and do not use http in production examples. Terminate TLS at a reverse proxy/load balancer.
  6. Limit Docker-host port exposure; bind services to localhost when appropriate or use an internal network plus a reverse proxy. Apply host firewall rules to restrict access.
  7. Protect health endpoints: restrict to internal network, require auth, or make them only accessible from the host (127.0.0.1) or via the load balancer.
  8. Rotate and revoke keys regularly and have an incident playbook ready. Enforce key rotation on compromise and use short-lived credentials where possible.
  9. Avoid storing long-lived API keys in plain text. Use ephemeral credentials or role-based access (e.g., IAM roles, STS) for cloud services when available.
  10. Audit usage of TRIGGER_SECRET_KEY and other workflow keys; treat them as high-value and rotate if exposed. Consider restricting Trigger.dev project scope and using environment-specific keys.
  11. Document and enforce secure deployment practices in the README: how to provision secrets, required IAM permissions, network restrictions (VPC/IP allowlist), and recommended monitoring/alerting.

🟡 apps/app/src/actions/organization/update-organization-logo-action.ts (MEDIUM Risk)

# Issue Risk Level
1 Client-provided Content-Type trusted without verification MEDIUM
2 No validation of file bytes/magic numbers MEDIUM
3 SVGs (image/svg+xml) allowed — XSS risk when rendered MEDIUM
4 No malware/virus scanning on uploaded files MEDIUM
5 Signed URLs valid for 3600s — potential exposure window MEDIUM
6 Uploaded S3 objects not deleted when logo removed MEDIUM
7 Base64 input not validated/checked for decoding errors MEDIUM
8 Filename sanitization permissive; may allow unexpected chars MEDIUM

Recommendations:

  1. Validate actual MIME/type by checking file magic bytes (e.g., use 'file-type' or 'magic-bytes' libraries) before trusting fileType and before uploading.
  2. Reject or specially-handle SVG uploads. Prefer raster formats (png/jpg) for logos, or sanitize/strip scripts from SVGs server-side (e.g., use DOM/SVG sanitizer).
  3. Do not directly trust client-provided Content-Type. Determine ContentType from inspected file bytes and set that when uploading to S3.
  4. Handle base64 decode errors and verify decoded buffer length and structure. Return a clear error on invalid base64 input.
  5. Add antivirus/malware scanning for uploaded files (e.g., ClamAV, vendor-managed scanning or cloud malware scanning) before storing/serving.
  6. Make uploaded S3 objects private by default and ensure the bucket/object ACLs and bucket policies prevent public access unless explicitly intended.
  7. Reduce signed URL lifetime (shorter than 3600s) or avoid returning signed URL to client; instead serve images through an authenticated proxy or via your app that enforces auth.
  8. On logo removal: delete the corresponding S3 object (or mark for async deletion) and/or implement an S3 lifecycle policy to remove orphaned objects to avoid stored sensitive content.
  9. Sanitize and normalize filenames more strictly: remove leading dots, collapse consecutive dots, limit length, and disallow characters that may be problematic. Consider generating server-side filenames/keys (UUIDs) rather than using client-provided names.
  10. Set server-side protections: enable server-side encryption, enable versioning if needed, and set S3 object metadata (Content-MD5) or checksums to verify integrity.
  11. Add logging/monitoring and alerts for suspicious uploads or repeated failed attempts to upload invalid files.

🔴 apps/app/src/app/(app)/[orgId]/auditor/(overview)/components/AuditorView.tsx (HIGH Risk)

# Issue Risk Level
1 Unvalidated logoUrl in href/src allows javascript: or data: URIs HIGH
2 Arbitrary external link may enable phishing or malicious downloads HIGH

Recommendations:

  1. Validate and normalize logoUrl before rendering: parse with the URL API and allow only http and https schemes. Reject or sanitize javascript:, data:, vbscript:, and other non-http(s) schemes.
  2. When linking to external resources, set target="_blank" and rel="noopener noreferrer" (or otherwise sandbox) to prevent tab-nabbing and to avoid providing window.opener access.
  3. Whitelist allowed image hosts or use Next.js Image optimization via remotePatterns or proxy the image through a trusted server to avoid loading attacker-controlled resources.
  4. Sanitize or limit length/characters of filenames used in the download attribute (the replace currently helps but consider additional restrictions).
  5. Add server-side validation/whitelisting for any user-controllable URLs before sending them to the client (defense in depth).

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

# Issue Risk Level
1 Unsanitized org.logo used directly as S3 Key (signed URL exposure) MEDIUM
2 DB-stored JSON parsed without schema validation MEDIUM
3 User-controlled DB content passed to frontend without sanitization (XSS risk) MEDIUM
4 parseRolesString uses 'r in Role' and may misparse roles enabling auth bypass MEDIUM
5 Silent catch blocks swallow errors, hiding failures and security signals MEDIUM
6 No explicit validation of orgId param before DB queries MEDIUM

Recommendations:

  1. Validate and whitelist organization.logo values before using them as S3 Keys. Ensure only allowed key prefixes or a strict mapping (store only filenames or object IDs, not arbitrary keys). Reject or normalize unexpected characters. If possible, store and use a server-side mapping from logo ID -> S3 key so users cannot control the raw key.
  2. Apply strict schema validation to JSON stored in the DB before calling JSON.parse and before using the parsed object. Use a runtime validator (zod, ajv, io-ts) and fail safely if the data does not conform to the expected shape.
  3. Treat DB-provided strings as untrusted when displayed in the UI. Prefer rendering as escaped text (React does this by default) and avoid dangerouslySetInnerHTML. If HTML is required, sanitize it with a well-maintained sanitizer (DOMPurify) and validate expected structure.
  4. Replace the loose parseRolesString check with an explicit mapping/validation. For example, normalize role strings to known canonical values and check equality against an allowed set (e.g., const allowed = new Set(Object.values(Role)); if (allowed.has(r)) ...). Avoid using the JavaScript 'in' operator on enums for auth checks.
  5. Do not leave empty catch blocks. Log errors (with appropriate sensitivity filtering) and handle failures explicitly. For operations that must succeed for security (e.g., auth/authorization checks), fail closed (deny access) when errors occur.
  6. Validate and coerce route parameters (organizationId) before using them in DB queries. Enforce expected formats (UUID, numeric ID, etc.) and return 400/404 on malformed values. Also ensure the ORM/DB layer is using parameterized queries (most ORMs do) to avoid injection risks.

🟡 apps/app/src/app/(app)/[orgId]/frameworks/lib/getPeople.ts (MEDIUM Risk)

# Issue Risk Level
1 Missing validation of organizationId before DB queries MEDIUM
2 Unvalidated fleetDmLabelId used in fleet API path MEDIUM
3 No input validation for employee fields or training IDs MEDIUM

Recommendations:

  1. Validate and sanitize organizationId (e.g., ensure it matches expected UUID format) before using in DB queries.
  2. Whitelist or validate employee.fleetDmLabelId and encode it (use encodeURIComponent) before interpolating into fleet API paths; restrict allowed characters/length.
  3. Add input schemas (zod/joi) for function parameters and important DB-derived fields (member.role, fleetDmLabelId, training video IDs) and validate DB data where it can be influenced by users.
  4. Although this code uses ORM findMany/findMany-style APIs (not raw SQL), ensure the ORM is used consistently and avoid any raw SQL (e.g., $queryRaw/$executeRaw) with untrusted inputs.
  5. Improve fleet API error handling and observability: log errors with context and consider retry/backoff; current catch sets device as not secure which is safe, but logging will help triage.
  6. When building lists from DB values (e.g., policy.signedBy), ensure the DB shape is as expected and normalize types before checks (avoid relying on implicit string formats).

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

# Issue Risk Level
1 Missing org membership authorization before querying org data HIGH
2 getControlTasks cached without session/org key — cross-tenant data leakage HIGH
3 Unvalidated orgId param used directly in DB queries HIGH
4 No 403/abort if member not found (allows authenticated access) HIGH

Recommendations:

  1. Enforce membership/authorization before reading or returning any org-scoped data. For example, check db.member (or an authorization service) early and return 403 if the session user is not a member or lacks the required role.
  2. Do not use a global server-side cache for per-session/per-organization queries without keying by the session/org. Either remove cache() from getControlTasks or include the organizationId (or session id + org id) in the cache key so results are isolated per-tenant.
  3. Validate the orgId route parameter (e.g., assert UUID format) and confirm ownership/membership before using it in DB queries. Treat route params as untrusted input and fail early if invalid.
  4. Return 403 (or redirect to an appropriate page) when the authenticated user is not a member of the requested organization. Do not continue to load org data or render org pages for non-members.
  5. Avoid fetching organization-scoped data (even minimally) before authorization checks. Move any lightweight org lookups (e.g., onboardingCompleted) behind a membership check, or limit returned fields to non-sensitive values that are safe to expose publicly.

🟡 apps/app/src/app/(app)/[orgId]/knowledge-base/page.tsx (MEDIUM Risk)

# Issue Risk Level
1 No validation of organizationId before DB queries MEDIUM
2 Relies solely on session.activeOrganizationId for access control MEDIUM
3 Returned DB content may be rendered unsanitized (XSS risk) MEDIUM

Recommendations:

  1. Validate and coerce organizationId type and format before queries
  2. Enforce server-side authorization checks per org and user roles
  3. Use parameterized queries/ORM to prevent injection
  4. Sanitize or escape DB content before rendering
  5. Log and monitor session anomalies and header validation

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

# Issue Risk Level
1 OrgId used directly in DB queries without validation MEDIUM
2 publicAccessToken read from cookie used without validation MEDIUM
3 parseRolesString uses 'in' check that may mis-validate roles MEDIUM

Recommendations:

  1. Validate and canonicalize route params (orgId) before use — e.g. enforce UUID format with a schema (zod/joi) or explicit regex. Reject or normalize malformed IDs before DB calls.
  2. Avoid relying solely on client-supplied tokens from cookies: validate any token server-side before using it to grant access or initialize state. If the token is meant to be secret, set it as HttpOnly, Secure and SameSite and verify signature/expiry on the server.
  3. If using an ORM/DB library, rely on parameterized queries (ORMs typically do) — but still validate input semantics (existence, ownership, format) to prevent enumeration or business-logic abuse.
  4. Replace the 'in' check for role parsing with a strict whitelist/lookup. For example, map input strings to known enum members explicitly (e.g. Role[input as keyof typeof Role] or a Set(['owner','admin','auditor']).has(input)) and reject unknown values.
  5. Log and rate-limit accesses to organization routes to slow enumeration attacks. Consider returning generic 404s for unauthorized org access to avoid revealing existence.
  6. For redirects: build internal URLs only from validated/canonical values. If you ever redirect to a path derived from user input, validate it against an allowlist to prevent open-redirects.

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

# Issue Risk Level
1 Unsanitized orgId used in DB query MEDIUM
2 Unsanitized orgId used in redirect (open redirect/path injection) MEDIUM
3 Unsafe role parsing and casting from DB string MEDIUM

Recommendations:

  1. Validate and canonicalize organizationId before use: enforce a strict pattern (e.g., UUID regex or numeric check) and reject or canonicalize unexpected values coming from params.
  2. Normalize types: coerce/validate organizationId to the expected DB type before passing to ORM (e.g., ensure it's a string matching the DB key format).
  3. For the redirect, build safe paths or whitelist allowed organization IDs. Encode path segments (e.g., encodeURIComponent(organizationId)) and/or validate organizationId against known orgs the user belongs to before redirecting.
  4. Avoid constructing redirect targets directly from unchecked input. Prefer server-side verification (confirm orgId belongs to session.user) then redirect to a fixed route template populated with a validated id.
  5. Tighten role parsing: avoid 'as Role[]' casts. Map parsed strings against an explicit set of allowed Role values and only return those verified values. Example: const allowed = new Set(Object.values(Role)); roles = parts.filter(p => allowed.has(p as Role)) as Role[];
  6. Store roles in a typed/normalized form (e.g., DB array or relation) so parsing is not required at runtime, removing parsing ambiguity.
  7. Ensure ORM queries remain parameterized (use the ORM's query builder methods) and do not interpolate params into raw SQL. If raw queries are necessary, use parameter binding.
  8. Add unit/integration tests that simulate malicious orgId values (../, //, %2F, very long strings, non-UUIDs) to ensure redirects and DB queries behave safely.

🔴 apps/app/src/app/(app)/[orgId]/policies/[policyId]/editor/components/PolicyDetails.tsx (HIGH Risk)

# Issue Risk Level
1 AI-proposed markdown stored without sanitization HIGH
2 Possible stored XSS when rendering TipTap/markdown content HIGH
3 No client/server validation shown before updatePolicy call HIGH

Recommendations:

  1. Sanitize markdown/HTML output before converting to TipTap
  2. Validate and escape content server-side in updatePolicy
  3. Render previews in a safe sandbox or escape HTML
  4. Require explicit user review/authorization before apply
  5. Apply CSP and input length/type limits

🟡 apps/app/src/app/(app)/[orgId]/policies/[policyId]/editor/components/ai/policy-ai-assistant.tsx (MEDIUM Risk)

# Issue Risk Level
1 No client-side input validation before sendMessage MEDIUM
2 Displays raw errorMessage to UI (may leak sensitive info) MEDIUM
3 Renders message parts without content-type checks (untrusted content) MEDIUM

Recommendations:

  1. Add client-side validation/sanitization for the prompt input before calling sendMessage: trim, enforce max length, allowed character set, and normalize whitespace. Treat client-side checks as UX improvements only — enforce the same validation server-side.
  2. On the server side, validate and canonicalize incoming messages. Apply rate limiting, authentication/authorization checks, and reject or sanitize payloads that exceed expected size or contain disallowed content.
  3. Do not expose raw internal error details to the UI. Map server errors to safe user-facing messages (e.g., "Something went wrong — try again") and log full details server-side (with proper access controls).
  4. When rendering messages, ensure the application never uses dangerouslySetInnerHTML or inserts HTML from untrusted sources. If any message parts can contain markup, parse and sanitize them with a vetted HTML sanitizer (e.g., DOMPurify) or render only plain text.
  5. Limit message part types and whitelist allowed tool/UI part names and fields. Validate tool input (e.g., summary/content) before rendering and truncate long strings.
  6. Add monitoring and alerting for unusual message size/frequency patterns and for any server-side sanitization failures.

🟢 apps/app/src/app/(app)/[orgId]/questionnaire/[questionnaireId]/components/QuestionnaireBreadcrumb.tsx (LOW Risk)

# Issue Risk Level
1 Unsanitized route param orgId used directly in href LOW
2 Unsanitized filename displayed and used in title attribute LOW

Recommendations:

  1. Validate and whitelist orgId on both client and server (e.g. allow only expected slugs or UUIDs via a regex like /^[a-zA-Z0-9-]+$/ or a strict UUID validator).
  2. When building dynamic path segments, encode the segment with encodeURIComponent (or use Next.js dynamic route helper APIs) so special characters cannot alter the URL structure: e.g. href={/${encodeURIComponent(orgId)}/questionnaire}.
  3. Sanitize filename before rendering: trim, restrict length, remove control characters (newlines, nulls, CR/LF, angle brackets) and/or whitelist allowed characters. Escape/encode any user-controlled text used in attributes (React does escaping by default, but sanitization reduces risk and improves UX).
  4. Ensure server-side authorization checks for orgId access (verify the current user is allowed to view resources for the given orgId) — do not rely on client-side checks.
  5. Add runtime guards for missing or malformed params (fallback UI if params.orgId or filename is undefined) and fail closed.
  6. If filenames may contain user-supplied HTML or markup in other contexts, use a proper sanitizer library (e.g., DOMPurify on the client or sanitize-html on the server) before injecting into the DOM.

🟡 apps/app/src/app/(app)/[orgId]/questionnaire/[questionnaireId]/data/queries.ts (MEDIUM Risk)

# Issue Risk Level
1 No validation of questionnaireId/organizationId before DB query MEDIUM
2 Unvalidated params used in ORM query (potential injection/abuse) MEDIUM
3 Coarse authorization: only activeOrganizationId checked, no role checks MEDIUM
4 Returns full questionnaire (answers/sources) => possible data exposure MEDIUM

Recommendations:

  1. Validate and sanitize questionnaireId and organizationId before use (e.g., require UUID format with a schema validator like zod/joi, or explicit regex/type checks).
  2. Rely on parameterized ORM calls (avoid raw SQL). Additionally, enforce input validation to prevent unexpected values or injection attempts and reject malformed IDs early.
  3. Add authorization checks beyond matching activeOrganizationId: verify user roles/permissions for reading questionnaire data (owner/editor/viewer scopes) and enforce least privilege.
  4. Limit returned fields to only what the caller needs. Do not include answers/sources unless the caller is authorized to view them. Introduce explicit select/projection or different endpoints for private data.
  5. Use an input schema (zod/joi) for route params, centralize validation, and convert/normalize inputs to typed values before DB calls.
  6. Log and standardize authentication/authorization failures (avoid leaking internal details in responses). Return consistent error responses (403/404) depending on whether resource existence should be concealed.
  7. If you must accept non-UUID ids, explicitly validate allowed formats and lengths to prevent abuse (e.g., extremely long strings).

🔴 apps/app/src/app/(app)/[orgId]/questionnaire/actions/answer-single-question.ts (HIGH Risk)

# Issue Risk Level
1 Unvalidated Referer/x-pathname header used in revalidatePath HIGH
2 Full URL or traversal chars may be passed to revalidatePath HIGH
3 Internal error messages returned to client HIGH
4 No max length or content constraints on question input HIGH
5 Revalidation invoked without explicit path authorization HIGH

Recommendations:

  1. Validate and sanitize the header-derived path before calling revalidatePath: parse the string and ensure it is a pathname only (starts with '/', no protocol/host), reject full URLs and strip query/hash. Reject or normalize any path containing '..' or other traversal sequences.
  2. Use a whitelist or enforce a fixed prefix for revalidation (e.g., only allow paths under a known base like /app/organizations/:orgId/...). Build the revalidation path from server-side data (session.organizationId and route template) rather than trusting headers.
  3. Remove direct leakage of internal Error messages to clients. Log full errors server-side, but return a generic message (e.g., 'Failed to answer question') and a stable error code to the client.
  4. Harden input schema for question: add constraints such as .min(1).max(N) (choose appropriate N), trim, and an allowed character pattern as needed. Validate other inputs (questionIndex, totalQuestions) for expected ranges.
  5. Ensure revalidation is authorized: confirm the computed path belongs to the active organization/session or otherwise verify permission before calling revalidatePath. Avoid revalidating arbitrary paths derived from request headers.
  6. Replace the brittle locale-strip regex (path.replace(//[a-z]{2}//, '/')) with explicit parsing/validation logic and unit tests covering malicious header values and edge cases.

🔴 apps/app/src/app/(app)/[orgId]/questionnaire/actions/create-trigger-token.ts (HIGH Risk)

# Issue Risk Level
1 createRunReadToken lacks ownership check for runId HIGH
2 createTriggerToken issues multi-use trigger tokens with broad scope HIGH
3 runId/taskId not validated or sanitized HIGH
4 Tokens issued without enforcing org scoping/authorization HIGH
5 Console.error may log sensitive details (stack/token) HIGH

Recommendations:

  1. Verify resource ownership before issuing tokens: look up the run by runId and confirm it belongs to session.session.activeOrganizationId (or the authenticated user) and refuse token creation if not.
  2. Scope tokens to the organization and resource: when calling the SDK to create tokens, include organization or resource scoping / constraints (if supported) so the token can only access runs/tasks for that org.
  3. Prefer least privilege and single-use tokens: avoid multipleUse:true unless strictly necessary. Use one-time tokens for triggers where possible and shorten expiration times (e.g., minutes instead of 1hr) based on use case.
  4. Validate inputs server-side: enforce allowed taskId values at runtime (not only via TypeScript) and validate runId format (UUID or expected pattern) before using it to create tokens.
  5. Add explicit authorization checks: require that session/session.activeOrganizationId exists and is used to authorize the specific token issuance (i.e., link token metadata to orgId and verify it).
  6. Avoid logging sensitive error details: redact tokens, stack traces, or any returned token-like strings from logs. Use structured logging with redaction or log only non-sensitive error codes/messages.
  7. Add issuance/audit logging and monitoring: record who requested the token, which resource it was for, timestamp, and token characteristics (single/multi-use, expiry) for audit and detection of misuse.
  8. If SDK supports metadata or custom claims, embed orgId and allowed run/task ids into the token so the token consumer can be validated against org context.

🔴 apps/app/src/app/(app)/[orgId]/questionnaire/actions/export-questionnaire.ts (HIGH Risk)

# Issue Risk Level
1 Spreadsheet formula injection in CSV and XLSX (cells starting with =,+,-,@) HIGH
2 No input size/length limits on questionsAndAnswers (DoS/memory exhaustion) HIGH
3 Entire file buffered and base64-encoded (high memory & response size) HIGH
4 No sanitization of text fields before PDF generation (content injection / layout/overflow issues) HIGH

Recommendations:

  1. Mitigate spreadsheet formula injection: before writing CSV/XLSX, detect cell values that start with '=', '+', '-', or '@' and prefix them with a single quote (') or an alternate safe prefix. For XLSX, set cell type to plain text ('t': 's') for all user-supplied cells (post-process the worksheet to set cell types and/or sanitize values).
  2. For CSV specifically, after escaping quotes, also prefix dangerous-leading characters with a single quote (') so Excel/Sheets treat them as text.
  3. Add strict input limits to the input schema: enforce a maximum array length (e.g., max number of QA pairs) and maximum string lengths for question and answer fields (zod .max(length)). Reject or truncate inputs that exceed limits.
  4. Avoid building entire files in memory for large exports: stream generation where possible (or generate and upload to object storage and return a signed URL). Do not return base64 data URLs for large files — instead return a URL or stream the response with proper content-type and content-disposition headers.
  5. Add rate limiting and request size limits on this endpoint (per-user and global) to mitigate abuse that could cause memory exhaustion.
  6. Sanitize/truncate content before PDF generation: remove control characters, cap maximum length per field, and/or escape unprintable characters. Consider truncating very long fields and adding a note that the content was truncated.
  7. Consider logging/monitoring large export requests and enforcing a max output file size. If PDF/CSV/XLSX must allow longer content, restrict to authenticated, authorized roles and require manual approval or background processing with storage.
  8. Add tests that verify formula-prefixing and cell-type enforcement so future changes don't reintroduce formula-injection risk.

🔴 apps/app/src/app/(app)/[orgId]/questionnaire/actions/parse-questionnaire-ai.ts (HIGH Risk)

# Issue Risk Level
1 Missing conditional validation for inputType fields (e.g., url required when inputType='url') HIGH
2 Unvalidated URLs forwarded to background task — potential SSRF when fetched HIGH
3 Unvalidated s3Key/fileName can enable object tampering or path traversal in S3 HIGH
4 No authorization checks for attachments/s3Key ownership (IDOR risk) HIGH
5 No file size/type limits or content scanning for base64 uploads (DoS/malware) HIGH
6 No rate limiting or abuse protection on task triggering HIGH
7 Re-throws raw errors, may leak internal error details HIGH

Recommendations:

  1. Make the input schema conditional: require url when inputType==='url', require fileData/fileName/fileType when inputType==='file', require attachmentId when inputType==='attachment', require s3Key (and optionally fileName/fileType) when inputType==='s3'. Use zod refinements or discriminated unions to enforce this.
  2. Validate and whitelist URLs before forwarding: enforce schemes (https), host whitelists, and block private IP ranges / localhost. Parse and resolve DNS to detect private addresses to mitigate SSRF.
  3. Validate and constrain s3Key/fileName: enforce an organization-scoped prefix (e.g., ${orgId}/...), disallow path traversal characters, and normalize keys before using them.
  4. Enforce ownership/authorization checks server-side for attachmentId and s3Key: verify the attachment/s3 object belongs to session.activeOrganizationId (or user) before passing identifiers to background tasks.
  5. Enforce file size and type limits for base64 uploads and for s3-sourced files; perform content-type checks and scan uploads with antivirus/malware scanning before processing.
  6. Add rate limiting / abuse protection around this action (per-user, per-org quotas) and consider throttling task creation to prevent DoS and runaway task costs.
  7. Avoid re-throwing raw internal Error objects to callers. Map internal errors to safe, high-level messages and log full details server-side (with correlation id) for debugging.

🔴 apps/app/src/app/(app)/[orgId]/questionnaire/actions/save-answer.ts (HIGH Risk)

# Issue Risk Level
1 Untrusted header used in revalidatePath (x-pathname/referer) allowing arbitrary path revalidation HIGH
2 User content synced to vector DB without sanitization or consent (data leakage risk) HIGH
3 No input size limits on answer/sources allowing large payloads (DoS/resource exhaustion) HIGH
4 Synchronous external sync blocks request thread, enabling blocking DoS HIGH

Recommendations:

  1. Whitelist and canonicalize revalidation paths. Do not use untrusted headers (x-pathname or Referer) directly; derive the path server-side or validate against a known set of allowed routes (ensure path starts with '/' and matches expected prefixes).
  2. Remove reliance on client-provided headers for revalidation. If you must accept a path, canonicalize and strictly validate it (e.g., regex + lookup against allowed routes) before calling revalidatePath.
  3. Queue vector sync operations as background jobs (e.g., job queue, worker) instead of awaiting them in the request handler. Alternatively, perform a fire-and-forget async call with proper error handling/timeouts so the main request is not blocked.
  4. Sanitize and redact sensitive content before sending to the vector DB. Implement PII detection/redaction and consider explicit user/organization consent for storing user-provided answers in external vector stores.
  5. Add explicit size/length limits to the zod schema (e.g., .max(length) for strings and .max(arrayLength) for arrays) and validate individual source fields to prevent large payloads and nested abuse.
  6. Introduce timeouts and circuit-breakers for external calls (syncManualAnswerToVector) and fail fast. Log and monitor slow/failed sync attempts.
  7. Rate-limit this endpoint and monitor revalidatePath usage to detect and block abuse or repeated revalidation requests from untrusted sources.
  8. If revalidation is necessary, perform it from a trusted backend context where the path is derived from server state (e.g., from the questionnaire record) rather than client headers.

💡 Recommendations

View 3 recommendation(s)
  1. Upgrade/patch vulnerable deps: update xlsx (remove 0.18.5) to a version that addresses GHSA-4r6h-8v6p-xvw6 and GHSA-5pgg-2g8v-p4x9, and update ai from 5.0.0 to >=5.0.52 which fixes GHSA-rwvc-j5jr-mgvh. Verify with the advisory fix versions and run tests after upgrade.
  2. Remove hardcoded credentials from the committed .env example (SELF_HOSTING.md): replace any real DATABASE_URL or API keys with placeholders (e.g. DATABASE_URL="postgres://<DB_USER>:<DB_PASS>@<DB_HOST>:<DB_PORT>/<DB_NAME>") and ensure the repo only contains non-sensitive examples.
  3. Mitigate spreadsheet formula injection in apps/app/src/app/(app)/[orgId]/questionnaire/actions/export-questionnaire.ts: when generating CSV/XLSX, detect values starting with '=', '+', '-', or '@' and prefix with a safe marker (e.g., a single quote) or force cell type to plain text before writing. Apply max length checks on fields to limit large payloads.

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

…e logic, change colors (#1840)

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
* feat(auditor): add auditor view page with AI-generated content

- Add new auditor page visible only to users with auditor role
- Implement role-based sidebar visibility (hide Settings/Integrations for auditor-only users)
- Add Trigger.dev task for generating auditor content sections
- Use Firecrawl for website scraping and GPT for content generation
- Add realtime progress tracking with useRealtimeRun hook
- Sections: Company Background, Services, Mission/Vision, System Description, Critical Vendors, Subservice Organizations

* chore(auditor): add layout and save content functionality for auditor view

- Create layout component for auditor view page
- Implement save action for auditor content with upsert functionality
- Enhance AuditorView component to handle content updates and display editable sections
- Integrate real-time content generation tracking and updates

* refactor(auditor): remove save-auditor-content action and update AuditorView

* refactor(auditor): simplify AuditorView component and remove orgId prop

* chore(organization): add actions for updating and removing organization logo

* refactor(onboarding): remove unnecessary blank line in backfill task

* feat(onboarding): add backfill queue for executive context task

* refactor(auditor): remove trigger-auditor-content action

* chore(onboarding): update message to reflect AI personalization

* chore(onboarding): update message to clarify AI personalization

* chore(env): add APP_AWS_ORG_ASSETS_BUCKET for organization static assets

---------

Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
…#1843)

Co-authored-by: Mariano Fuentes <marfuen98@gmail.com>
@Marfuen Marfuen merged commit 7391136 into release Nov 26, 2025
11 of 12 checks passed
@claudfuen
Copy link
Contributor

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