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.

@vercel
Copy link

vercel bot commented Nov 24, 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 24, 2025 11:04pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
portal (staging) Skipped Skipped Nov 24, 2025 11:04pm

@CLAassistant
Copy link

CLAassistant commented Nov 24, 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.

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

@comp-ai-code-review
Copy link

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

🔒 Comp AI - Security Review

🔴 Risk Level: HIGH

2 high CVEs in xlsx@0.18.5 (Prototype Pollution GHSA-4r6h...; ReDoS GHSA-5pgg...) and 1 low CVE in ai@5.0.0 (filetype whitelist bypass GHSA-rwvc..., fixed in 5.0.52).


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

🔴 apps/app/src/actions/safe-action.ts (HIGH Risk)

# Issue Risk Level
1 Client-controlled metadata.name can bypass rate limiting HIGH
2 Trusting X-Forwarded-For header for ratelimit and audit HIGH
3 Sensitive user input logged via JSON.stringify HIGH
4 Re-throwing raw server errors may leak internals HIGH
5 RevalidatePath uses untrusted header path allowing abuse HIGH
6 Client-controlled metadata.track can spoof analytics events HIGH
7 Audit log stores full client input including sensitive fields HIGH

Recommendations:

  1. Validate and canonicalize metadata.name server-side. Do not allow the client to specify action names used to bypass server-side policies; use a server-side allowlist or map client action identifiers to server-known actions.
  2. Construct rate-limit keys from trustworthy, server-controlled values (e.g., authenticated user ID, session ID, organization ID) or from proxy-validated client IPs. If you must use an IP, obtain it from a trusted proxy header (configured at the proxy/load-balancer) and validate it; do not trust arbitrary X-Forwarded-For values from untrusted clients.
  3. Redact or omit sensitive fields before logging. Maintain a list of sensitive field names (password, token, ssn, email, personal data) and strip/replace them before JSON.stringify to logs and audit records. Consider structured logging with explicit fields rather than dumping the whole input.
  4. Return generic error messages to clients. Wrap internal errors and log full details server-side, but throw a generic error message (or an error code) to the client to avoid leaking stack traces or internal implementation details.
  5. Whitelist and canonicalize revalidation targets. Do not revalidate arbitrary paths from request headers. Maintain a server-side allowlist of allowed routes (or derive revalidation path from known resources) and validate/sanitize the path before calling revalidatePath.
  6. Sanitize/normalize analytics metadata coming from the client. Do not allow arbitrary event names/channels from the client to be recorded without server-side validation. Map client-intent to server-known event names or drop unsupported events.
  7. Redact sensitive input before persisting to audit logs. Audit logs should store minimal necessary context (user id, action, safe metadata, reference to resource id) and avoid storing raw client-provided payloads (or store encrypted/redacted payloads).
  8. Use a stronger rate-limiting key composition: combine authenticated user ID (or organization+member ID) with action name and a normalized IP where applicable, rather than relying solely on a header value that can be spoofed.
  9. Consider stricter metadata schema validation (zod) to explicitly disallow or constrain fields that can alter security behavior (e.g., disallow client-supplied event names or action categories unless mapped server-side).

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/actions/answer-single-question.ts (MEDIUM Risk)

# Issue Risk Level
1 Arbitrary path revalidation via attacker-controlled headers MEDIUM
2 User input passed to answerQuestion without sanitization MEDIUM
3 No length limits on question -> possible resource exhaustion (DoS) MEDIUM
4 No bounds checks for questionIndex/totalQuestions MEDIUM
5 Returns raw error.message to client exposing internal info MEDIUM

Recommendations:

  1. Do not trust request headers for control operations. Build a whitelist of allowed paths and validate/normalize the path server-side before calling revalidatePath. Prefer deriving the path from server-side context or a known-safe mapping instead of using x-pathname or referer headers.
  2. Apply content validation/sanitization to 'question' beyond type-checking. Use zod refinements (e.g., .max(length), regex) to enforce allowed characters/size and reject or sanitize unexpected payloads before forwarding to answerQuestion.
  3. Enforce maximum length on question (z.string().max(N)) and/or stream/limit input sizes at the HTTP boundary to mitigate large payload memory exhaustion. Consider server-side upload/size limits and request throttling/rate limiting for this action.
  4. Validate numeric bounds for questionIndex and totalQuestions (e.g., z.number().int().min(0).max(totalMax)), and verify relative invariants (questionIndex < totalQuestions). Reject or clamp out-of-range values prior to business logic.
  5. Avoid returning raw error.message to clients. Return generic error responses (e.g., 'Failed to answer question') and log full details (stack/message) server-side with correlation IDs for debugging. Do not expose internal error contents or upstream errors in responses.
  6. Review the implementation of answerQuestion to ensure it safely handles forwarded input: use parameterized queries for DB access, escape shell/command invocations, and sanitize any content used in external calls. Add unit tests and fuzz tests for injection cases.
  7. Add monitoring/alerting for unusual revalidation calls and large/rapid requests to this endpoint to detect abuse/DoS attempts.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/actions/save-answer.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated header used for revalidatePath enabling cache revalidation abuse MEDIUM
2 User answer and sources stored without sanitization (stored XSS risk) MEDIUM
3 Casting sources to any bypasses type checks before DB write MEDIUM
4 Error logging may leak sensitive data via raw error messages MEDIUM

Recommendations:

  1. Validate/whitelist the path before calling revalidatePath. Do not use raw request headers (x-pathname or referer) directly. Compute/derive the path server-side when possible or check it against a known set of routes (or a per-organization whitelist).
  2. Sanitize or canonicalize user-provided strings (answer and source fields) before storing, and/or ensure all outputs escaping HTML when rendering. Apply size limits and trim inputs.
  3. Tighten the zod schema for sources (explicit types, max lengths, required/optional fields) and avoid casting sources to any. Validate each source object explicitly and transform to the DB DTO shape rather than bypassing type checks.
  4. Avoid logging raw error objects/stack traces in production. Redact or log only non-sensitive error codes/messages and correlate with an internal error ID. Use structured logging with controlled fields.
  5. Protect revalidation operations: require proper authorization checks, rate-limit revalidate endpoints/operations, and log revalidation requests for audit.
  6. Add server-side checks before upserting manual answers (e.g., normalize question text, enforce deduplication limits) to avoid unintended data pollution.

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

# Issue Risk Level
1 Inconsistent ownership checks: update uses id only, may modify others' answers HIGH
2 QuestionAnswer lookup may not enforce organization ownership HIGH
3 Untrusted header (referer/x-pathname) used in revalidatePath HIGH
4 No size/length limits on 'answer' and 'sources' — potential large-payload DoS HIGH
5 Error logs may expose raw error messages or internal IDs HIGH

Recommendations:

  1. Use ownership constraints in the update WHERE clause (include questionnaireId and/or organizationId) or perform the update via a single guarded query (e.g., a single UPDATE ... WHERE id = ? AND questionnaireId = ? AND questionnaire.organizationId = ?) to avoid TOCTOU and ensure you can't update a record you didn't validate.
  2. Ensure the question-answer lookup enforces ownership correctly. If using Prisma: use findUnique only with truly unique keys or use findFirst/findMany with an explicit where that includes questionnaireId and join/verify questionnaire.organizationId equals activeOrganizationId. Prefer a single backend-enforced query to validate-and-update.
  3. Do not trust client-supplied headers for revalidation paths. Validate and normalize the path against a whitelist of allowed revalidation routes, strip dangerous characters, and fall back to a server-known path when missing or invalid.
  4. Enforce input size limits in the Zod schema: add max length to 'answer' (e.g., .max(5000)) and place limits on the 'sources' array length and on string sizes inside each source. Also apply server-side limits before database writes and when calling sync to the vector DB to prevent large-payload or high-cost operations.
  5. Avoid logging raw error objects or sensitive internal IDs in production logs. Mask or redact sensitive fields (organizationId, userId, internal DB IDs) and log errors with minimal messages and a correlation id. Use structured logging with non-sensitive correlation IDs and ensure logs abide by your data protection policy.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/components/QuestionnaireUpload.tsx (MEDIUM Risk)

# Issue Risk Level
1 Client-side file validation (type/size) only; can be bypassed MEDIUM
2 No server-side validation or malware scanning for uploads MEDIUM
3 User-supplied filename rendered; sanitize/truncate before use MEDIUM

Recommendations:

  1. Enforce server-side validation of file type, size, and contents regardless of client checks. Do not rely on client-side Dropzone limits (maxSize/maxFiles/accept).
  2. Perform content-based validation on the server (magic-byte/mime sniffing) in addition to checking extensions and reported MIME types.
  3. Scan uploaded files for malware/viruses (e.g., ClamAV, commercial AV, or cloud scanning services) before any processing or storage.
  4. Sanitize, normalize, and truncate filenames before storing or displaying. Prefer generating server-side safe storage filenames (UUIDs) and persist the original name separately after sanitization/truncation.
  5. Escape/normalize user-supplied strings when rendering in the UI and enforce a reasonable max length to avoid UI issues or disclosure of long payloads.
  6. Return clear server-side rejection errors for invalid/unsafe files so the client cannot assume success based only on client-side checks.
  7. Apply rate limits, authentication and authorization checks to upload endpoints; require ACLs and CSRF protections as appropriate.
  8. Store uploads in a location with least privilege, scan on-access if necessary, and avoid serving uploaded files directly without validation or a signed URL mechanism.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/usePersistGeneratedAnswers.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated metadata sent to updateAnswerAction MEDIUM
2 Unvalidated result answers/sources sent to updateAction MEDIUM
3 Potential stored XSS from saving raw answer or sources MEDIUM
4 Client trusts autoAnswerRun.metadata from external source MEDIUM
5 No input schema validation before enqueueing updates MEDIUM

Recommendations:

  1. Treat autoAnswerRun.metadata as untrusted. Validate and coerce its shape with a schema (e.g., Zod/Typebox/Joi) before using values like questionIndex, answer, and sources.
  2. Sanitize/normalize answers and sources on the client if needed for UX, but enforce robust server-side validation and sanitization before persisting (reject or canonicalize unexpected types/values).
  3. On the server, always validate questionnaireId ownership and authorization; never rely on client-side checks. Ensure updateAnswerAction (server handler) enforces authorization.
  4. Escape/encode answers and any source content when rendering in the UI to prevent stored XSS (e.g., do not dangerouslySetInnerHTML with raw values; HTML-encode strings).
  5. Use parameterized queries / ORM protections on the server to avoid injection risks when persisting data; log and fail-safe on validation errors.
  6. Add explicit rate-limiting and exponential backoff/retry logic for update operations to reduce abuse and accidental rapid writes.
  7. Add logging/alerts for malformed metadata or repeated failed update attempts so suspicious input sources can be investigated.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireActions.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated file upload data sent to server MEDIUM
2 No client-side file size/type checks before read/upload MEDIUM
3 Trusts server-provided downloadUrl and filename without validation MEDIUM

Recommendations:

  1. Client-side validation before reading/sending files: enforce allowed MIME types and extensions, enforce a maximum file size and reject files outside those constraints in handleFileSelect/handleParse.
  2. Sanitize filename before using it in the DOM or logs: strip path components and control characters, restrict to a safe whitelist of characters, and/or let the server set Content-Disposition/filename for downloads instead of trusting client-side filename values.
  3. Validate downloadUrl before triggering an automatic click: allow only expected schemes (e.g., blob:, data:, or same-origin/signed URLs) or fetch the file from the server and create an object URL via URL.createObjectURL for download rather than directly using a server-provided href.
  4. Perform full server-side validation and scanning of uploaded file contents and metadata (type/size/magic bytes), and enforce server-side size limits or streaming uploads to prevent large uploads/exhaustion.
  5. Require and verify authentication/authorization on upload/export actions on the server; ensure server-side checks do not rely on client-side behavior.
  6. Avoid executing or navigational side effects directly from untrusted server strings. Treat server-provided URLs and names as untrusted input and carefully validate or normalize them before DOM use.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireAutoAnswer.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated external metadata used to setResults (possible XSS/state poisoning) MEDIUM
2 autoAnswerToken used in client code (risk of secret leakage) MEDIUM
3 Metadata fields (question/answer/sources) not validated before saving or processing MEDIUM

Recommendations:

  1. Validate and strictly type autoAnswerRun.metadata with a schema validator (zod/joi/ts-json-schema) before using it to update React state. Reject or coerce unexpected types/fields.
  2. Sanitize/escape any metadata-derived strings at the rendering boundary. Prefer React's default string rendering and avoid dangerouslySetInnerHTML; if HTML must be rendered, sanitize it with a well-maintained HTML sanitizer (e.g., DOMPurify).
  3. Treat autoAnswerToken as sensitive. Avoid exposing long-lived secrets to the browser — run privileged task triggers server-side, or use short-lived, limited-scope tokens that cannot be exfiltrated or reused. If client usage is required, ensure the token is ephemeral, minimal-scope, and rotated frequently.
  4. Validate and enforce server-side input contracts when persisting answers (saveAnswersBatchAction). Do not trust client-provided metadata; re-validate structure and content server-side before saving to the DB or forwarding to other services.
  5. Normalize/whitelist accepted sourceTypes and other enumerations from metadata; do not trust unbounded arrays/objects from external metadata.
  6. Add logging and alerting on unexpected metadata shapes or token usage patterns to detect possible tampering or exfiltration attempts.
  7. Consider adding a Content Security Policy (CSP) to mitigate the impact of any potential XSS vectors.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireDetail/useQuestionnaireDetailHandlers.ts (MEDIUM Risk)

# Issue Risk Level
1 Unsanitized question/answer sent to backend (injection risk) MEDIUM
2 No server-side authorization enforced client-side before actions MEDIUM
3 triggerAutoAnswer/triggerSingleAnswer calls not awaited; async errors unhandled MEDIUM
4 vendorId built by concatenating organizationId without validation MEDIUM
5 Queue processing race allows duplicate or unexpected requests MEDIUM
6 Incomplete delete handler and missing finalization MEDIUM

Recommendations:

  1. Sanitize/validate question and answer payloads before sending (client-side for UX/defense-in-depth, but enforce strict server-side validation and escaping). Example: trim, enforce max length, remove/escape control characters, validate expected character sets and JSON structure.
  2. Enforce server-side authorization/permission checks for every action (updateAnswer, deleteAnswer, auto-answer triggers). Do not rely on client checks; validate organizationId belongs to authenticated user and that user has write permissions.
  3. Treat triggerAutoAnswer/triggerSingleAnswer as asynchronous: have them return Promises and await them (or handle their returned Promises). Wrap awaits in try/catch to handle failures and roll back/update UI state. Example: await triggerAutoAnswer(...).catch(...) and ensure questionStatuses/isAutoAnswerProcessStarted are reconciled on failure.
  4. Validate and canonicalize organizationId before embedding into vendorId. Don’t build critical identifiers by naive concatenation of user-controlled input. If vendorId must be derived, use server-side generation or strict validation/whitelisting of organizationId (allow only known chars and length).
  5. Harden queue processing: deduplicate indices before enqueueing, enforce a max queue size, and use atomic state updates or a queue data-structure managed with refs to avoid race conditions. Ensure processNextInQueue checks and updates state atomically (or use a reducer). On failures, ensure the queue and questionStatuses are reconciled.
  6. Improve delete handler finalization: ensure all related client state is updated (questionStatuses, answerQueue) and handle cases where deleteAnswerAction.execute may be void or reject later. On failure, roll back UI state. Consider returning/awaiting server acknowledgement before marking UI success and calling router.refresh.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireDetail/useQuestionnaireDetailState.ts (MEDIUM Risk)

# Issue Risk Level
1 Trigger token stored in client state (autoAnswerToken exposed) MEDIUM
2 User input sent to server actions without sanitization/validation MEDIUM
3 Token usable from client enables abuse if leaked or via XSS/CSRF MEDIUM
4 No input size/content limits for answers (allow large payloads) MEDIUM

Recommendations:

  1. Do not store or surface sensitive trigger tokens in client-accessible state. Create the trigger token and invoke orchestration server-side (or store tokens in httpOnly cookies or server-only env) so the client never directly holds the token.
  2. Enforce server-side validation and sanitization for all inputs received by actions (updateQuestionnaireAnswer, deleteQuestionnaireAnswer, create-trigger-token endpoints). Treat client data as untrusted regardless of any client-side checks.
  3. Scope tokens to the minimum required permissions and short expirations. Rotate tokens regularly and bind them to server-side session/identity where possible. If the client must initiate a process, have it call a server endpoint that verifies authorization and uses the token server-side.
  4. Protect token-triggered endpoints with proper CSRF defenses and require authenticated/authorized requests. Do not rely solely on obscurity of tokens in the client.
  5. Enforce input size and content limits both client- and server-side (max length, allowed characters, reject binary/huge payloads). Implement rate limiting and request throttling on endpoints that accept free-text answers.
  6. Harden against XSS so that stored tokens cannot be exfiltrated (output-encode UI, use Content Security Policy, avoid injecting untrusted HTML into the page).

🔴 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireParse.ts (HIGH Risk)

# Issue Risk Level
1 Trigger tokens created/exposed in client state (createTriggerToken) HIGH
2 Run read token stored/exposed client-side (createRunReadToken) HIGH
3 No validation/sanitization of run.output fields (questionnaireId, questions) HIGH
4 No validation of upload response fields (s3Key, fileName, fileType) HIGH
5 Displays raw server error messages in toasts (possible info leak) HIGH
6 Uses orgId/questionnaireId directly in router.push without validation HIGH

Recommendations:

  1. Do not return long-lived or powerful trigger/run tokens to the browser. Create tokens server-side (or via dedicated backend endpoints) and only return a minimal-scope, short-TTL credential if absolutely necessary.
  2. Avoid persisting tokens in client storage/state where they can be exfiltrated by XSS. Keep any required tokens ephemeral and in-memory for the shortest time needed; prefer server-side polling/webhooks for task status instead of exposing read tokens to the client.
  3. Validate and strictly type-check run.output before use. Apply schema validation (e.g., zod, yup, io-ts) to verify questionnaireId is a valid identifier, questionsAndAnswers is an array of properly-shaped objects, and extractedContent is a string. Reject/mask unexpected fields.
  4. Validate upload responses on the server and verify S3 keys/file metadata before returning them to the client. On the client, validate types and sanitize fileName/fileType; treat s3Key as opaque and avoid passing unchecked values into downstream operations.
  5. Do not display raw server error payloads to end users. Show generic error messages (e.g., 'Failed to parse questionnaire') and log the detailed server error on the server or to a secure logging service. If including any server text in UI, escape/encode it and redact sensitive details.
  6. Sanitize and validate path components before calling router.push. Use strict canonical checks (e.g., allowlist/regex for orgId and questionnaireId), or use encodeURIComponent for dynamic segments. Prefer passing route objects (pathname + query) where supported to avoid accidental path manipulation.
  7. Harden client XSS protections: ensure all user- or server-provided strings are safely escaped when rendered, enable Content Security Policy (CSP), and perform regular XSS testing on pages that render parsed questionnaire content.

🔴 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireParser.ts (HIGH Risk)

# Issue Risk Level
1 Sensitive tokens stored in client state (parseToken, autoAnswerToken) HIGH
2 Tokens and parseTaskId passed to client hooks can leak via client logs or network HIGH
3 Client can trigger parse/auto-answer actions that may be callable without server auth checks HIGH
4 File upload state (selectedFile) lacks explicit validation before upload HIGH
5 Unsanitized searchQuery/results filtering may lead to XSS when rendered HIGH

Recommendations:

  1. Remove long-lived or sensitive tokens from client-accessible JS state. Use short-lived tokens or keep them server-side and proxy requests through authenticated server endpoints.
  2. Use HttpOnly, Secure cookies (and SameSite as appropriate) for auth/session tokens to prevent JavaScript access. If tokens must be used in client, minimize lifetime and scope.
  3. Ensure all server endpoints invoked by client actions (parse, auto-answer, upload) enforce authentication and authorization server-side. Do not rely on client-side checks.
  4. Validate and sanitize uploaded files on the server: check MIME type, file extension, size limits, and scan for malicious content. Also consider client-side pre-checks for UX but enforce on server.
  5. Treat all data rendered into the DOM as untrusted. Escape text when injecting into HTML, or use a vetted sanitizer (e.g., DOMPurify) before inserting HTML. Prefer rendering as text nodes rather than using innerHTML.
  6. Avoid logging sensitive tokens or identifiers on the client or sending them in URLs. Use POST bodies or headers for sensitive data where possible and ensure transport uses HTTPS.
  7. Add rate limiting, CSRF protections, and server-side input validation for actions that trigger background tasks (parse/auto-answer) to prevent abuse or resource exhaustion.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireSingleAnswer.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated user question sent to server action MEDIUM
2 Server action response stored without sanitization — stored XSS risk MEDIUM
3 Unvalidated inputs may enable SQL injection in server actions MEDIUM
4 Answer saved to DB without server-side validation or parameterization MEDIUM
5 No authorization checks visible before saving answers MEDIUM

Recommendations:

  1. Treat all data coming from the client as untrusted. Enforce server-side validation and sanitization for question, answer, ids and any other payloads. Use a schema validator (eg. Zod, Yup) in the server action handlers.
  2. Ensure server actions that persist data use parameterized queries or an ORM to avoid SQL injection. Do not rely on client-side validation to prevent injection.
  3. Encode/escape or sanitize answers and any HTML-like content before storing or rendering to prevent stored XSS. Consider storing raw data plus a sanitized/escaped rendering version as appropriate.
  4. Enforce authorization and permission checks inside server actions (server-side). The client should not be trusted to enforce who can save or modify questionnaire answers.
  5. Add comprehensive server-side error handling and logging for failed saves and generation attempts. Consider rate-limiting, request de-duplication, and locking to avoid race conditions.
  6. Audit the implementations of answerSingleQuestionAction and saveAnswerAction to confirm they perform validation, sanitization, parameterized DB access, and proper auth checks.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/knowledge-base/manual-answers/components/ManualAnswersSection.tsx (MEDIUM Risk)

# Issue Risk Level
1 No client-side validation of manualAnswerId before deleteAction.execute MEDIUM
2 window.location.hash is used directly to compute element IDs MEDIUM
3 Route param orgId used directly in href without validation MEDIUM
4 No visible CSRF protection for destructive actions MEDIUM
5 No client-side authorization check before delete operations MEDIUM

Recommendations:

  1. Server-side: Enforce strict validation and authorization for all destructive actions (deleteManualAnswer, deleteAllManualAnswers). Never rely on client-side checks for security.
  2. Server-side: Validate manualAnswerId (format, existence) and verify the current user/org is authorized to perform the delete. Return appropriate errors if not authorized.
  3. CSRF: Ensure the action endpoints require proper CSRF protection (anti-CSRF tokens or use same-site session cookies + server-side validation). If next-safe-action or your framework provides built-in CSRF protections, verify and document that they are enabled.
  4. Input handling: Treat window.location.hash as untrusted input. Validate/sanitize the parsed manualAnswerId before using it in logic (even if only for getElementById/scrolling), and guard against unexpected characters. Consider a whitelist (e.g., alphanumeric/UUID) or prefix matching.
  5. Route params: Validate orgId (format and membership) server-side before performing actions referenced by links or actions. If needed, sanitize when rendering links, although rendering alone is low-risk — the server must always enforce ownership/authorization.
  6. Client UX: Add optimistic UI indicators and clear error handling for delete failures. Disable delete UI controls until authorization/validations are confirmed by the server if desired.
  7. Audit: Verify what next-safe-action/useAction provides (CSRF, auth propagation). If it automatically handles CSRF or auth tokens, document and ensure correct configuration; otherwise implement server-side mitigations.

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

# Issue Risk Level
1 No validation of session.activeOrganizationId before data queries MEDIUM
2 Access control relies solely on session.activeOrganizationId MEDIUM
3 Headers() forwarded without filtering to auth.api.getSession MEDIUM
4 No error handling around Promise.all data fetches MEDIUM
5 Potential data exposure if downstream queries trust orgId MEDIUM

Recommendations:

  1. Verify that session.session.activeOrganizationId is authorized for session.user.id (e.g., check user's membership/role in the organization) before using it for queries. Do not rely on presence alone.
  2. Enforce authorization checks in the data layer (getPublishedPolicies, getContextEntries, getManualAnswers, getKnowledgeBaseDocuments) so each query validates the calling user's permission to access the specified organization data.
  3. Filter/whitelist headers (or explicitly extract only required header values) before passing to auth.api.getSession to avoid leaking or trusting unexpected client-controlled headers.
  4. Wrap the parallel fetches in try/catch and handle individual failures gracefully. Consider Promise.allSettled if you need partial results, and ensure failures do not leak sensitive error details to clients.
  5. Validate and sanitize organizationId before using it in downstream queries. Treat it as untrusted data unless verified against the authenticated user's permissions.
  6. Add logging and monitoring for access attempts across organization boundaries to detect and alert on suspicious access patterns.

💡 Recommendations

View 3 recommendation(s)
  1. Upgrade packages: bump ai to the fixed release (>= 5.0.52) and update package.json + lockfile, then run CI tests.
  2. Upgrade xlsx from 0.18.5 to a release that addresses GHSA-4r6h-8v6p-xvw6 and GHSA-5pgg-2g8v-p4x9 (per the advisories); update lockfile and test parsing code paths.
  3. While upgrading, locate all code paths that import/use xlsx and harden them: enforce server-side file-size limits, validate file/mime bytes before parsing, and wrap parsing in try/catch or a worker/sandbox to reduce Prototype Pollution and ReDoS impact until the dependency is updated.

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

* fix(security-questionnaire): implement double-click protection and improve parsing state management

* fix(file-uploader): remove unnecessary padding from uploader component

* refactor(security-questionnaire): clean up auto-answer hook by removing debug logging and optimizing metadata handling

* refactor(security-questionnaire): add parse process state management

* feat(security-questionnaire): implement manual answer linking and update questionnaire components

* fix(security-questionnaire): enable CTA button for navigating to policies page

* feat(docs): create documentation (without video)

* refactor(security-questionnaire): normalize results and update button states

* refactor(parse-questionnaire): enhance chunk processing and question extraction logic

---------

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 24, 2025

🔒 Comp AI - Security Review

🔴 Risk Level: HIGH

OSV: 2 HIGH CVEs in xlsx@0.18.5 and 1 LOW CVE in ai@5.0.0. Code: SQL injection in questionnaire page and multiple stored XSS (page.tsx, save-answer.ts, update-questionnaire-answer.ts).


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

🔴 apps/app/src/actions/safe-action.ts (HIGH Risk)

# Issue Risk Level
1 Raw clientInput and results logged, risking PII and secret leaks HIGH
2 Unsanitized clientInput saved into audit logs/DB (stored XSS/log injection) HIGH
3 Rate-limit key uses x-forwarded-for header which is easily spoofed HIGH
4 Multiple actions excluded from ratelimit allowing DoS abuse HIGH
5 revalidatePath uses untrusted header path, enabling arbitrary revalidation HIGH
6 metadata.name accepted from client without whitelist (can be abused) HIGH
7 Audit logs may store large or malicious payloads (resource exhaustion) HIGH

Recommendations:

  1. Avoid logging full raw inputs/results. Redact or omit sensitive fields (PII, auth tokens, file contents) before JSON.stringify. Implement a whitelist of safe fields and a global sanitizer that redacts secrets.
  2. Sanitize and validate clientInput before storing in audit logs. Enforce an allowlist of expected fields and types (zod schema for inputs), escape/encode content when it will be rendered, and reject or truncate unexpected fields.
  3. Don't rely on untrusted X-Forwarded-For directly for rate-limiting keys. Use authenticated user id (ctx.user.id) or a proxy-populated trusted IP header (e.g., X-Real-IP validated by your ingress) as the rate-limit key. If IP must be used, validate/trust it only when coming from known proxies.
  4. Reconsider excluding actions from rate limiting. Apply per-user quotas or per-organization quotas for these actions, or require additional checks (CAPTCHA, stricter per-user rate limit) to prevent abuse while preserving UX.
  5. Whitelist and normalize revalidation targets. Do not call revalidatePath with unchecked header values. Derive revalidation paths from server-side known routes or validate against a list/pattern (e.g., /^/app(/.*)?$/) and enforce max length.
  6. Validate metadata.name against an allowlist of known action names or patterns in defineMetadataSchema. Deny or normalize unexpected names to prevent abuse (e.g., varying names to bypass limits or pollute logs).
  7. Limit audit log size and enforce storage quotas. Reject or truncate inputs exceeding size limits, and apply sanitization to prevent log/DB injection. Consider streaming large file contents to blob storage and only store references in audit logs.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/[questionnaireId]/page.tsx (MEDIUM Risk)

# Issue Risk Level
1 SQL injection via getQuestionnaireById using unsanitized route params MEDIUM
2 Stored XSS risk: questionnaire filename/questions passed to client unescaped MEDIUM
3 Missing validation of route params before DB/query use MEDIUM
4 Org ID comparison may be bypassed by type/format mismatch MEDIUM

Recommendations:

  1. Validate and sanitize questionnaireId and orgId server-side
  2. Use parameterized queries/ORM to prevent SQL injection
  3. Escape or sanitize questionnaire fields before rendering client
  4. Normalize and enforce types/format when comparing org IDs
  5. Return 403 for unauthorized access and log auth failures

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/actions/save-answer.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated header used in revalidatePath MEDIUM
2 Potential cache revalidation abuse via x-pathname or referer header MEDIUM
3 Stored user content (answer/sources) not sanitized — persistent XSS risk MEDIUM
4 Unsafe any cast for sources before DB write MEDIUM
5 Large/unchecked input sizes (answer/sources) risk DoS or DB bloat MEDIUM
6 Error messages logged directly may leak sensitive info MEDIUM

Recommendations:

  1. Validate and whitelist the path before calling revalidatePath. Parse the header value as a URL (new URL(...)) when appropriate and only use the pathname portion. Ensure the final path begins with '/' and matches an allowlist of application routes or a safe regex.
  2. Normalize and strictly restrict which headers are accepted for revalidation. Prefer an internal source of truth for the current path (e.g., from the server-side router or DB) rather than trusting x-pathname or referer. Rate‑limit revalidation requests to mitigate abuse.
  3. Tighten the input schema: extend the zod schema to enforce maximum lengths and structural limits (e.g., answer: z.string().max(2000).nullable(), sources: z.array(...).max(10).optional()). Validate nested fields (sourceName, documentName, policyName) with explicit length/type constraints.
  4. Remove the unsafe any cast for sources. Define a proper TypeScript/Prisma type or zod schema for sources and pass typed/validated data to the DB (avoid (sources as any)).
  5. Treat user-provided content as untrusted. Store raw text but ensure the frontend always HTML-encode/escape values on render. If rich text is needed, sanitize it server-side with a well-reviewed sanitizer and a strict allow-list of tags/attributes.
  6. Avoid logging raw error messages or user content. When logging, redact sensitive fields and capture structured errors with minimal detail (or send full stack only to a secure error monitoring system with access controls).
  7. Make expensive/optional work (e.g., syncManualAnswerToVector) asynchronous or queued. If synchronous is required, add timeouts, retries with backoff, and monitoring so it cannot block the main flow or be leveraged for DoS.
  8. Ensure DB operations are bounded (e.g., limit number of sources and their sizes) to prevent storage bloat and excessive CPU work while indexing/embedding.
  9. Add server-side rate limiting on endpoints that accept large payloads or trigger heavy downstream operations (revalidation, vector DB sync).

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/actions/update-questionnaire-answer.ts (MEDIUM Risk)

# Issue Risk Level
1 IDOR: update uses id-only where clause, may bypass org check MEDIUM
2 Insecure cache revalidation via user-controlled x-pathname/referer header MEDIUM
3 Header-derived path not validated before revalidatePath (DoS/abuse) MEDIUM
4 Unrestricted error logging may leak sensitive info MEDIUM

Recommendations:

  1. Include organizationId (or questionnaireId) in the DB update where clause for questionnaireQuestionAnswer.update (defense-in-depth) to prevent a TOCTOU/IDOR window: e.g. where: { id: questionAnswerId, questionnaireId }.
  2. Avoid using untrusted request headers directly for cache revalidation. Only revalidate known/whitelisted paths or derive the revalidation target from server-side state (e.g., resolve path from questionnaireId or internal routing map).
  3. Validate and canonicalize the path before calling revalidatePath (ensure it begins with expected prefix, remove path traversal, limit length, and verify it maps to an application route). Consider rate-limiting and/or requiring elevated permissions for revalidation operations.
  4. Sanitize or redact sensitive content from logs (stack traces, raw errors, user data). Log structured, non-sensitive identifiers (IDs, error codes) and send full error details to secured error tracking/observability systems with access controls.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/components/QuestionnaireUpload.tsx (MEDIUM Risk)

# Issue Risk Level
1 Client-side file type/size checks only (bypassable) MEDIUM
2 No server-side malware/virus scanning for uploads MEDIUM
3 Untrusted filenames sent/displayed without sanitization MEDIUM
4 No client-side auth check before uploading (possible unauthorized uploads) MEDIUM

Recommendations:

  1. Always validate file type and size on the server side (do not rely on client-side Dropzone accept/maxSize). Reject non-conforming uploads.
  2. Perform server-side content inspection (check magic bytes / file signatures) to verify declared MIME type and format.
  3. Integrate malware/virus scanning (e.g., ClamAV, commercial AV services, or cloud provider scanning) on uploaded files before processing or storing them.
  4. Sanitize and normalize filenames on the server (strip/replace problematic characters, limit length). Do not use user-supplied filenames as filesystem paths or include them in HTML without escaping. Prefer storing files with generated safe IDs and store original name as metadata after sanitization.
  5. Enforce authentication and authorization for upload endpoints server-side. Do not rely on client-side checks for access control. Verify the caller's identity and permissions before accepting uploads.
  6. Rate-limit and monitor upload endpoints and validate file contents before triggering further processing to limit abuse.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/usePersistGeneratedAnswers.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated autoAnswerRun.metadata forwarded to backend MEDIUM
2 User-controlled result.answer and sources sent to updateAction MEDIUM
3 No input validation before calling enqueueUpdate/executeAsync MEDIUM

Recommendations:

  1. Enforce server-side validation and authorization for the update endpoint invoked by updateAnswerAction.executeAsync. The server must treat all client-provided fields (questionnaireId, questionAnswerId, answer, sources, status) as untrusted and validate types, lengths, and authorized ownership before persisting.
  2. Add strict client-side validation as a defense-in-depth measure (e.g., use Zod/io-ts) to validate autoAnswerRun.metadata, result.answer, and sources shapes: enforce maximum lengths, allowed characters, and expected types (string/array/UUID/number).
  3. Normalize and sanitize 'sources' entries (strip unexpected fields, validate score ranges, allowed sourceType/sourceName values). Reject or canonicalize nested objects or unexpected data.
  4. Validate questionAnswerId format and existence before sending (e.g., ensure it matches expected UUID or numeric pattern). Prefer waiting for authoritative id from server; keep pendingUpdatesWaitingForId flow but validate once id present.
  5. Limit and canonicalize answer content: impose length caps, remove/encode scripts or dangerous markup (to prevent stored XSS when answers are rendered), and reject control characters and binary blobs.
  6. Log and alert on malformed or unexpected metadata keys/values, and on repeated failures from enqueueUpdate to detect abuse or injection attempts.
  7. Ensure the server uses parameterized queries and avoids string interpolation when persisting answer data to prevent SQL injection. Escape or encode outputs when rendering answers in the UI to prevent XSS.
  8. Ensure the updateAnswerAction endpoint requires authentication/authorization and verifies the caller is allowed to modify the specific questionnaire/questionAnswer.
  9. Consider rate-limiting/queueing and backoff for update endpoints to limit abuse from automated submissions.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireActions.ts (MEDIUM Risk)

# Issue Risk Level
1 No file validation before upload (type/size/content) MEDIUM
2 Unsanitized fileName sent to server (possible server-side injection) MEDIUM
3 User answers/results sent to triggerAutoAnswer without sanitization MEDIUM
4 saveAnswerAction/single-answer payloads sent unsanitized to server MEDIUM
5 Server-provided downloadUrl/filename used directly to create and click a link MEDIUM

Recommendations:

  1. Validate files both client- and server-side: enforce allowed MIME types, extension whitelist, and maximum file size. Reject or quarantine suspicious file contents and consider virus/malware scanning on the server.
  2. Sanitize and normalize filenames before sending to or using on the server: strip control and path separator characters, limit length, and consider replacing with server-generated safe filenames or using UUIDs. Validate fileType on the server rather than trusting the client-provided MIME.
  3. Treat questionnaire content and answers as untrusted input. Validate length and acceptable characters client-side for UX, but enforce comprehensive validation and sanitization server-side. Escape or encode data before reflecting it in any HTML, SQL, command, or shell context.
  4. Use parameterized queries / prepared statements on the server for any database writes to eliminate SQL injection. For any downstream systems (shell, exec, templates), avoid concatenation of user input; use safe APIs or strict whitelisting.
  5. When using server-provided download URLs and filenames in the browser, validate the URL scheme and origin (disallow javascript: and other unsafe schemes). Prefer returning either a blob payload or a signed, time-limited URL from the server, and sanitize filename before using it in download attribute. Consider setting rel="noopener noreferrer" and target attributes if opening new windows, and use safe blob URLs created via URL.createObjectURL for untrusted content.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireAutoAnswer.ts (MEDIUM Risk)

# Issue Risk Level
1 Unvalidated autoAnswerRun.metadata consumed directly MEDIUM
2 questionIndex not bounds-checked before indexing results MEDIUM
3 Answer strings are not sanitized (XSS risk on render) MEDIUM
4 Unvalidated metadata forwarded to save actions MEDIUM

Recommendations:

  1. Validate metadata schema and types server/client-side
  2. Clamp/check questionIndex within results length
  3. Sanitize/escape answer strings before saving or rendering
  4. Verify autoAnswerToken scope and authenticate task runs
  5. Add server-side validation before persisting batch answers

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireDetail/useQuestionnaireDetailHandlers.ts (MEDIUM Risk)

# Issue Risk Level
1 No input sanitization before sending questions to backend MEDIUM
2 triggerSingleAnswer called without try/catch or response handling MEDIUM
3 triggerAutoAnswer invoked with no success/failure handling MEDIUM
4 No client-side rate limiting for batch auto-answer requests MEDIUM
5 Queue and state refs can cause race conditions / duplicate triggers MEDIUM
6 vendorId built client-side as org_${organizationId} is guessable MEDIUM

Recommendations:

  1. Treat all client-side data as untrusted and enforce server-side validation and sanitization for question and answer payloads (length limits, acceptable chars, strip/escape markup as appropriate).
  2. Await or otherwise handle the return value of triggerAutoAnswer/triggerSingleAnswer (or ensure those functions internally handle errors). Wrap async calls in try/catch and propagate failures to user-visible error states.
  3. If triggerAutoAnswer returns a Promise, do not rely on synchronous try/catch; use async/await or .catch() to handle rejections. Provide success/failure callbacks so UI state (questionStatuses, isAutoAnswerProcessStarted, refs) can be correctly updated on completion/failure.
  4. Implement client-side throttling/debouncing and enforce server-side rate limits for auto-answer endpoints to prevent abuse/accidental flooding. Consider exponential backoff and circuit-breaker behavior for repeated failures.
  5. Mitigate race conditions in queue processing by using atomic operations or a mutex/lock for queue consumption. Avoid relying solely on refs + setState with timeouts; prefer a single source of truth and functional state updates, and ensure processNextInQueue cannot be re-entered concurrently.
  6. Do not assume vendorId constructed on the client is authoritative. Perform server-side validation/authorization for vendorId/organizationId and do not use guessable identifiers as a sole access control mechanism.
  7. Add timeouts/abort signals and retry policies for network requests, and ensure UI state (processing/completed) is updated in all success/failure code paths to prevent stuck processing states.

🟡 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireDetail/useQuestionnaireDetailState.ts (MEDIUM Risk)

# Issue Risk Level
1 Missing validation: user answers sent to update action without sanitization MEDIUM
2 Trigger tokens stored in client state may expose sensitive tokens MEDIUM
3 No client-side authorization checks before invoking update/delete actions MEDIUM

Recommendations:

  1. Validate and sanitize inputs server-side in the updateQuestionnaireAnswer and deleteQuestionnaireAnswer actions. Do not rely on client-side trimming/validation alone. Use a whitelist approach for allowed content/length and enforce escaping when rendering answers to prevent XSS.
  2. Treat trigger tokens as sensitive secrets. Do not persist them in client-accessible state if they grant any privileged operations. Instead: issue short-lived, scoped tokens; perform sensitive operations server-side; or store tokens in HttpOnly cookies or use server-side proxy/orchestrator endpoints so tokens never land in browser JS.
  3. Enforce authorization and authentication on the server side for update and delete actions (check user identity, organization membership, permissions). Client-side checks may be added for UX but must not be the sole enforcement.
  4. Add output encoding/escaping in any place that renders user-provided answers or question data (to protect against stored XSS).
  5. Limit token scope and lifetime, rotate tokens regularly, and audit which backend processes can create/consume trigger tokens. Log and monitor token usage for anomalies.

🔴 apps/app/src/app/(app)/[orgId]/security-questionnaire/hooks/useQuestionnaireParse.ts (HIGH Risk)

# Issue Risk Level
1 Privileged trigger/read tokens are created/stored on client HIGH
2 Client-stored tokens can be exfiltrated via XSS HIGH
3 User-visible toasts disclose raw server error messages HIGH
4 Unvalidated server response used in navigation (orgId/questionnaireId) HIGH
5 S3 upload response fields used without validation (s3Key, fileName, fileType) HIGH

Recommendations:

  1. Move sensitive token creation and exchange to server-side endpoints. The client should request short-lived, scoped credentials from the server (e.g., via an API that creates a token and returns only what is necessary). Avoid creating privileged trigger/read tokens directly in client code.
  2. Never persist privileged tokens in client-accessible JS state if they grant more privileges than needed. If tokens must be delivered to the client, use HttpOnly, Secure cookies or very short-lived tokens with strict scopes and rotate them frequently.
  3. Harden the application against XSS to prevent token exfiltration: enable a strict Content Security Policy (CSP), sanitize/escape any user-controllable data rendered into the page, and minimize use of innerHTML or other direct DOM insertion methods.
  4. Avoid displaying raw server error messages to end users. Log full error details server-side (with secure access controls) and show generic, user-friendly messages in the UI (e.g., 'Failed to start parse task').
  5. Validate and sanitize any values coming from server responses before using them in navigation or API calls. For questionnaireId: validate format (allowed characters, length), and URL-encode or otherwise ensure it cannot inject path segments. Use a canonical ID format (UUID) if possible.
  6. For S3 response fields (s3Key, fileName, fileType): validate types and formats (string length, allowed characters, MIME type whitelist) before using them as parameters to further actions. Do not trust client-side values — enforce validation again server-side when those values are used to access resources.
  7. When calling router.push with server-provided values, build the route using safe encoding (e.g., encodeURIComponent on path segments) or use route parameters that enforce allowed patterns so arbitrary path injection isn't possible.
  8. Ensure server-side endpoints that accept s3Key/fileName/fileType or questionnaireId verify ownership/authorization: confirm the requesting user/org is allowed to access or act upon the referenced resource.
  9. Consider minimizing the information returned in run.output and upload responses to only what the client strictly needs to operate, or deliver sensitive identifiers via server-signed references that expire.

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

# Issue Risk Level
1 No authorization/role checks beyond presence of activeOrganizationId MEDIUM
2 Session-derived orgId passed to client component (possible info leak) MEDIUM
3 Missing error handling around parallel data fetching MEDIUM

Recommendations:

  1. Enforce proper authorization checks/ACLs before returning organization-specific data. Verify the authenticated user has the required role/permissions for organizationId (not just that an activeOrganizationId exists in session).
  2. Limit exposure of internal identifiers to the client. If the org ID must be sent to the browser, use an obfuscated/public identifier (e.g., a UUID or mapping) or ensure the receiving components are server-only and do not serialize the raw internal ID into client-side JavaScript/HTML.
  3. Wrap the Promise.all data fetch in try/catch and return safe error states. Handle partial failures gracefully (e.g., fallbacks or per-resource error handling) and avoid leaking stack traces or internal error details to the client.
  4. Ensure the data-access layer (getPublishedPolicies, getContextEntries, getManualAnswers, getKnowledgeBaseDocuments) enforces parameter validation and uses parameterized queries/prepared statements to avoid injection risks should any input become attacker-controlled.

🟢 apps/app/src/app/(app)/[orgId]/security-questionnaire/knowledge-base/published-policies/components/PublishedPoliciesSection.tsx (LOW Risk)

# Issue Risk Level
1 Missing validation of route param orgId before use LOW

Recommendations:

  1. Validate and sanitize params.orgId before using it to build URLs. Ensure it matches the expected pattern (e.g., alphanumeric/org id pattern) and provide a safe fallback if invalid.
  2. Add null/undefined checks and fallbacks for orgId to avoid unexpected hrefs or runtime errors.
  3. Perform server-side authorization checks when fetching policies to ensure the requester is allowed to see the org's policies (do not rely solely on client-side routing).
  4. When building URLs from dynamic data, canonicalize/encode path segments (e.g., encodeURIComponent) to avoid malformed paths.
  5. Continue to validate/escape policy fields on the server when saving them (enforce length/type limits and strip disallowed content).
  6. Consider restricting opening links in new tabs to trusted destinations; at minimum keep rel="noopener noreferrer" (already present) and validate that linked IDs produce safe internal routes.

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

# Issue Risk Level
1 Feature-flag and session checks lack explicit org authorization MEDIUM

Recommendations:

  1. Explicitly verify the user is authorized for the organizationId on every server-side request (e.g., query membership/role in DB or assert organizationId present in a server-validated session record). Do not rely solely on session.activeOrganizationId without a server-side membership check.
  2. In getQuestionnaires and any other data access, require organizationId be validated against a server-side membership / org record before returning organization-scoped data.
  3. Limit forwarded headers to only what auth.getSession needs (typically cookies or authorization headers). Avoid blindly forwarding all headers if your auth helper expects a specific token container.
  4. Continue to use parameterized ORM queries (as done with db.policy.count), and avoid string concatenation for SQL/filters. Ensure getQuestionnaires also uses parameterized queries and does not build raw SQL with interpolated values.
  5. Encode organizationId when inserting into URLs if it's possible for org IDs to contain unsafe characters (percent-encode path segments). If org IDs are constrained to a safe format (UUID, numeric, or alphanumeric slug), validate/normalize them on the server and document the constraint.

💡 Recommendations

View 1 recommendation(s)
  1. Upgrade vulnerable packages immediately: bump ai to >=5.0.52 (per advisory) and update xlsx to a release that addresses GHSA-4r6h-8v6p-xvw6 and GHSA-5pgg-2g8v-p4x9; re-run your OSV/audit tooling and regenerate the lockfile.",

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

…1825)

Co-authored-by: Tofik Hasanov <annexcies@gmail.com>
@vercel vercel bot temporarily deployed to staging – portal November 24, 2025 23:01 Inactive
@Marfuen Marfuen merged commit 807445e into release Nov 24, 2025
11 of 12 checks passed
@claudfuen
Copy link
Contributor

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

4 participants