Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docker/demo/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Database password for PostgreSQL. Use a random 32+ character string.
POSTGRES_PASSWORD=change-me-to-a-random-32-char-string

# Secret used to sign NextAuth sessions and to derive the initial encryption key.
# Use a random 32+ character string. Generate with: openssl rand -base64 32
NEXTAUTH_SECRET=change-me-to-a-random-32-char-string

# VF_VERSION pins the server image tag (default: latest).
#VF_VERSION=1.2.3
54 changes: 54 additions & 0 deletions docker/demo/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
services:
postgres:
container_name: vectorflow-demo-postgres
image: timescale/timescaledb:latest-pg16
environment:
POSTGRES_DB: vectorflow
POSTGRES_USER: vectorflow
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U vectorflow"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped

vectorflow:
container_name: vectorflow-demo-server
image: ghcr.io/terrifiedbug/vectorflow-server:${VF_VERSION:-latest}
depends_on:
postgres:
condition: service_healthy
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://vectorflow:${POSTGRES_PASSWORD}@postgres:5432/vectorflow
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
NEXTAUTH_URL: https://demo.vectorflow.sh
AUTH_TRUST_HOST: "true"
VF_DEMO_MODE: "true"
volumes:
- vfdata:/app/.vectorflow
- backups:/backups
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health/ready"]
interval: 30s
timeout: 5s
start_period: 30s
retries: 3
deploy:
resources:
limits:
memory: 1g
cpus: "2.0"
restart: unless-stopped

volumes:
pgdata:
name: vectorflow-demo-pgdata
vfdata:
name: vectorflow-demo-data
backups:
name: vectorflow-demo-backups
11 changes: 8 additions & 3 deletions docker/server/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ NEXTAUTH_SECRET=change-me-to-a-random-32-char-string

# ── Optional ──────────────────────────────────────────────────

# Set to your canonical URL in production (e.g., https://vectorflow.example.com)
# When unset, AUTH_TRUST_HOST=true infers the URL from the Host header.
#NEXTAUTH_URL=http://localhost:3000
# Canonical public URL of this deployment (e.g., https://vectorflow.example.com).
# Required for OAuth/OIDC callback URLs and "reset password" email links to resolve
# correctly. AUTH_TRUST_HOST=true (set in docker-compose.yml) allows the server to
# infer the URL from the X-Forwarded-Host header when this is unset, but setting it
# explicitly is strongly recommended for any public deployment.
# The hosted demo uses docker/demo/docker-compose.yml which hardcodes
# NEXTAUTH_URL=https://demo.vectorflow.sh. For all other deployments set this:
#NEXTAUTH_URL=https://vectorflow.example.com

# Server port (default: 3000)
#PORT=3000
Expand Down
1 change: 1 addition & 0 deletions docker/server/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ services:
DATABASE_URL: postgresql://vectorflow:${POSTGRES_PASSWORD}@postgres:5432/vectorflow
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
NEXTAUTH_URL: ${NEXTAUTH_URL}
AUTH_TRUST_HOST: "true"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Host-header injection risk from AUTH_TRUST_HOST with optional NEXTAUTH_URL

When AUTH_TRUST_HOST is "true" and NEXTAUTH_URL is absent or empty, NextAuth v5 infers its canonical URL from the X-Forwarded-Host / Host request header. In this compose, NEXTAUTH_URL comes from an optional env var with no required default, so Docker passes an empty string when operators omit it. An attacker who can reach port 3000 directly and inject a crafted X-Forwarded-Host header can make NextAuth treat their domain as a valid callback origin, enabling open-redirect and OAuth callback-hijacking.

The demo compose avoids this correctly by hardcoding the canonical URL. The server compose should either remove AUTH_TRUST_HOST (operators who need it can add it themselves when they also set NEXTAUTH_URL), or enforce that NEXTAUTH_URL is provided using Docker Compose's ${VAR:?error message} required-variable syntax, which aborts startup with a clear error if the variable is unset.

Prompt To Fix With AI
This is a comment left during a code review.
Path: docker/server/docker-compose.yml
Line: 32

Comment:
**Host-header injection risk from `AUTH_TRUST_HOST` with optional `NEXTAUTH_URL`**

When `AUTH_TRUST_HOST` is `"true"` and `NEXTAUTH_URL` is absent or empty, NextAuth v5 infers its canonical URL from the `X-Forwarded-Host` / `Host` request header. In this compose, `NEXTAUTH_URL` comes from an optional env var with no required default, so Docker passes an empty string when operators omit it. An attacker who can reach port 3000 directly and inject a crafted `X-Forwarded-Host` header can make NextAuth treat their domain as a valid callback origin, enabling open-redirect and OAuth callback-hijacking.

The demo compose avoids this correctly by hardcoding the canonical URL. The server compose should either remove `AUTH_TRUST_HOST` (operators who need it can add it themselves when they also set `NEXTAUTH_URL`), or enforce that `NEXTAUTH_URL` is provided using Docker Compose's `${VAR:?error message}` required-variable syntax, which aborts startup with a clear error if the variable is unset.

How can I resolve this? If you propose a fix, please make it concise.

volumes:
- vfdata:/app/.vectorflow
- backups:/backups
Expand Down
Loading