Author: Bar Shimshon (Support Team)
Project: roboflow-support
Review Date: 2026-01-26
Reviewer: Tony França / Jarbas (AI Assistant)
The Support Debug Website is an internal Next.js application created by a support team member to help with debugging and customer investigations. While the initiative is commendable, the application has critical security vulnerabilities and architectural issues that must be resolved before it can be considered production-ready.
Verdict: ❌ NOT PRODUCTION READY
Requirement: Backend must not persist data to local filesystem. All state should be in external storage.
Findings:
- ✅ Production uses GCS via
src/lib/storage.tsabstraction ⚠️ Terminal sessions stored in-memory (src/lib/terminal-session.ts) - lost on restart⚠️ Audit logs written to local filesystem in dev mode
Files affected:
src/lib/storage.ts- Good abstraction, switches between GCS (prod) and filesystem (dev)src/lib/terminal-session.ts- In-memory Map for session storage
Recommendation: Migrate terminal sessions to Redis or Firestore for persistence across restarts.
Requirement: Secrets must come from environment variables. Sensitive secrets should use Secret Manager.
Findings:
- ✅ API keys loaded from environment variables
⚠️ Not using Google Secret Manager- ❌ Hardcoded fallback secret in
terminal-session.ts:const JWT_SECRET = process.env.TERMINAL_JWT_SECRET || 'your-secret-key-change-in-production';
Files affected:
src/lib/terminal-session.ts- Hardcoded fallback secretsrc/lib/auth.ts- Uses env vars correctlysrc/lib/intercom.ts,src/lib/linear.ts,src/lib/claude.ts- Use env vars correctly
Recommendation:
- Remove all hardcoded fallback secrets
- Migrate sensitive secrets to Google Secret Manager
- Use
@google-cloud/secret-managerclient library
Requirement: All access to production GCS/Firestore must go through the backend, not directly from frontend.
Findings:
- ✅ All GCS operations go through API routes
- ✅ All Firestore operations go through API routes
- ✅ Frontend makes fetch calls to
/api/*endpoints - ✅ No direct client-side GCP SDK usage
Files verified:
src/lib/storage.ts- Server-side onlysrc/lib/firestore.ts- Server-side onlysrc/app/api/*- All data access is server-side
Requirement: Backend must NOT use gcloud CLI commands. Must use client libraries.
Findings:
- ❌ VIOLATION: Multiple files use
child_process.exec()to rungcloudcommands
Affected files:
src/lib/gcp-auth.ts:
const { stdout } = await execAsync('gcloud auth print-access-token');
await execAsync(`gcloud config set project ${projectId}`);src/app/api/gcs-scan/route.ts:
const { stdout } = await execAsync(`gcloud storage ls "gs://${bucket}/${prefix}**"`);src/app/api/dataset-recovery/route.ts:
const { stdout } = await execAsync(`gcloud storage ls ...`);Recommendation:
- Replace
gcloud auth print-access-tokenwith Application Default Credentials or Workload Identity - Replace
gcloud storage lswith@google-cloud/storageclient library - Remove all
child_process.exec()calls for GCP operations
Requirement: Logs should go to Google Cloud Logging with structured format, not console.log.
Findings:
⚠️ 112 occurrences ofconsole.logacross the codebase⚠️ 67 occurrences ofconsole.error- ❌ No structured logging
- ❌ No Google Cloud Logging integration
Recommendation:
- Integrate
@google-cloud/loggingor use structured stdout logging - Use log levels (info, warn, error) consistently
- Add request correlation IDs for tracing
Requirement: Must use Google SSO. Must have allowlist for who can access (not just @roboflow.com domain).
Findings:
- ✅ Google OAuth SSO implemented via NextAuth.js
- ✅ Domain restriction to @roboflow.com in
src/lib/auth.ts:
if (!email || !email.endsWith('@roboflow.com')) {
return false; // Deny sign-in
}- ❌ NO USER ALLOWLIST - Any @roboflow.com email can access
⚠️ Audit logging exists but basic
Recommendation:
- Implement user allowlist (config file or database)
- Add role-based access control if needed
- Consider using Google Groups for access management
Requirement: CI/CD must be configured for automated deployments.
Findings:
- ✅
cloudbuild.yamlpresent and configured - ✅ Builds Docker image and deploys to Cloud Run
- ✅ Service account configured
File: cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'gcr.io/$PROJECT_ID/support-dashboard', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'gcr.io/$PROJECT_ID/support-dashboard']
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
args: ['gcloud', 'run', 'deploy', ...]Requirement: No security vulnerabilities, especially in user input handling.
Findings:
// Line 67 - User input directly in shell command
const { stdout } = await execAsync(`gcloud storage ls "gs://${bucket}/${prefix}**"`);Attack vector:
prefixcomes from request body without sanitization- Attacker can inject:
"; rm -rf / #or$(malicious_command)
const { stdout } = await execAsync(`gcloud storage ls "gs://${bucket}/${prefix}"`);Same vulnerability pattern.
await execAsync(`tar -xzf ${tempFile} -C ${tempDir}`);If tempFile path is influenced by user input, this is exploitable.
Recommendation:
- IMMEDIATELY remove all
exec()calls with user input - Use client libraries instead of CLI commands
- If shell commands are absolutely necessary, use proper escaping libraries
- Implement input validation and sanitization
- Consider using a security linter (e.g.,
eslint-plugin-security)
| Requirement | Status | Priority |
|---|---|---|
| Stateless Backend | Medium | |
| Secrets Management | Medium | |
| Production Data Access | ✅ | - |
| No gcloud CLI | ❌ | Critical |
| Logging | Low | |
| Authentication Allowlist | High | |
| Automated Deployment | ✅ | - |
| Security (Command Injection) | ❌ | Critical |
-
Remove command injection vulnerabilities
- Replace all
exec()calls with client libraries - Files:
gcs-scan/route.ts,dataset-recovery/route.ts,jetson-diag/route.ts,gcp-auth.ts
- Replace all
-
Remove gcloud CLI usage
- Use
@google-cloud/storagefor GCS operations - Use Application Default Credentials for auth
- Use
- Implement user allowlist
- Add config for allowed users/groups
- Don't rely solely on domain restriction
-
Remove hardcoded secrets
- Remove fallback in
terminal-session.ts - Consider migrating to Secret Manager
- Remove fallback in
-
Migrate terminal sessions to persistent storage
- Use Redis or Firestore
- Implement structured logging
- Integrate Cloud Logging
- Add correlation IDs
The Support Debug Website shows good initiative and has some solid architectural decisions (storage abstraction, NextAuth.js for auth, CI/CD setup). However, the critical security vulnerabilities (command injection) and architectural violations (gcloud CLI in backend) make it unsuitable for production in its current state.
The most urgent fixes are:
- Remove all command injection vectors
- Replace gcloud CLI with client libraries
- Implement user allowlist
Once these are addressed, a follow-up review should be conducted before production deployment.