From e9cd11735cce3318282a72c0850e8a1c14d3ff21 Mon Sep 17 00:00:00 2001 From: Vectry Date: Tue, 10 Feb 2026 16:53:57 +0000 Subject: [PATCH] security: fix trace ownership bypass and externalize secrets to .env - Add userId guard in trace upsert to prevent cross-user overwrites - Move AUTH_SECRET, STRIPE_WEBHOOK_SECRET, POSTGRES_PASSWORD to .env - docker-compose.yml now references env vars instead of hardcoded secrets - Add .env.example with placeholder values for documentation --- .env.example | 16 ++++++++++++++++ apps/web/src/app/api/traces/route.ts | 7 ++++++- docker-compose.yml | 18 +++++++++--------- 3 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..22b2a81 --- /dev/null +++ b/.env.example @@ -0,0 +1,16 @@ +# Authentication +AUTH_SECRET= # Generate with: openssl rand -base64 32 + +# Stripe +STRIPE_SECRET_KEY= # sk_live_... or sk_test_... +STRIPE_WEBHOOK_SECRET= # whsec_... +STRIPE_STARTER_PRICE_ID=price_1SzJUlR8i0An4Wz7gZeYgzBY +STRIPE_PRO_PRICE_ID=price_1SzJVWR8i0An4Wz755hBrxzn + +# Database (optional — defaults to agentlens/agentlens/agentlens) +POSTGRES_USER=agentlens +POSTGRES_PASSWORD= +POSTGRES_DB=agentlens + +# Email (optional — email features disabled if not set) +EMAIL_PASSWORD= diff --git a/apps/web/src/app/api/traces/route.ts b/apps/web/src/app/api/traces/route.ts index d582a7f..1b2d218 100644 --- a/apps/web/src/app/api/traces/route.ts +++ b/apps/web/src/app/api/traces/route.ts @@ -241,9 +241,14 @@ export async function POST(request: NextRequest) { for (const trace of body.traces) { const existing = await tx.trace.findUnique({ where: { id: trace.id }, - select: { id: true }, + select: { id: true, userId: true }, }); + // Security: prevent cross-user trace overwrite + if (existing && existing.userId !== userId) { + continue; // skip traces owned by other users + } + const traceData = { name: trace.name, sessionId: trace.sessionId, diff --git a/docker-compose.yml b/docker-compose.yml index 39d67f1..eb16b44 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,13 +8,13 @@ services: environment: - NODE_ENV=production - REDIS_URL=redis://redis:6379 - - DATABASE_URL=postgresql://agentlens:agentlens@postgres:5432/agentlens - - AUTH_SECRET=Ge0Gh6bObko0Gdrzv+l0qKHgvut3M7Av8mDFQG9fYzs= + - DATABASE_URL=postgresql://${POSTGRES_USER:-agentlens}:${POSTGRES_PASSWORD:-agentlens}@postgres:5432/${POSTGRES_DB:-agentlens} + - AUTH_SECRET=${AUTH_SECRET} - AUTH_TRUST_HOST=true - STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY:-} - - STRIPE_WEBHOOK_SECRET=whsec_ZGT3JCrEK6GWP3cIMvYfrfLplZ3rMn0m - - STRIPE_STARTER_PRICE_ID=price_1SzJUlR8i0An4Wz7gZeYgzBY - - STRIPE_PRO_PRICE_ID=price_1SzJVWR8i0An4Wz755hBrxzn + - STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET} + - STRIPE_STARTER_PRICE_ID=${STRIPE_STARTER_PRICE_ID:-price_1SzJUlR8i0An4Wz7gZeYgzBY} + - STRIPE_PRO_PRICE_ID=${STRIPE_PRO_PRICE_ID:-price_1SzJVWR8i0An4Wz755hBrxzn} - EMAIL_PASSWORD=${EMAIL_PASSWORD:-} depends_on: redis: @@ -45,9 +45,9 @@ services: postgres: image: postgres:16-alpine environment: - - POSTGRES_USER=agentlens - - POSTGRES_PASSWORD=agentlens - - POSTGRES_DB=agentlens + - POSTGRES_USER=${POSTGRES_USER:-agentlens} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-agentlens} + - POSTGRES_DB=${POSTGRES_DB:-agentlens} volumes: - agentlens_postgres_data:/var/lib/postgresql/data healthcheck: @@ -72,7 +72,7 @@ services: target: builder command: npx prisma db push --schema=packages/database/prisma/schema.prisma --skip-generate environment: - - DATABASE_URL=postgresql://agentlens:agentlens@postgres:5432/agentlens + - DATABASE_URL=postgresql://${POSTGRES_USER:-agentlens}:${POSTGRES_PASSWORD:-agentlens}@postgres:5432/${POSTGRES_DB:-agentlens} depends_on: postgres: condition: service_healthy