Skip to content
Merged
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
24 changes: 21 additions & 3 deletions apps/api/plane/settings/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,27 @@

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# Secret Key
SECRET_KEY = os.environ.get("SECRET_KEY", get_random_secret_key())
_logger = logging.getLogger("plane")

# Secret Key — use `or` so an explicitly empty env var is treated the same as unset,
# falling back to a random key rather than passing "" to Django (GHSA-cmwv-pjmw-8483).
SECRET_KEY = os.environ.get("SECRET_KEY") or get_random_secret_key()
# Refuse to run silently with a publicly-known or placeholder SECRET_KEY
# (GHSA-cmwv-pjmw-8483). Emit a critical log so operators notice immediately.
# The `or get_random_secret_key()` above means the only way to reach this branch
# is if the environment explicitly passes one of the flagged values.
_INSECURE_SECRET_KEYS = {
"60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5", # old publicly-known default
"change-this-key-on-deployment", # placeholder shipped in community templates
}
if SECRET_KEY in _INSECURE_SECRET_KEYS:
_logger.critical(
"SECURITY: SECRET_KEY is set to a known insecure or placeholder value. "
"This makes your installation vulnerable to session forgery, CSRF bypass, and "
"password-reset token forging. Set a unique SECRET_KEY before deploying to production. "
"Generate one with: "
"python3 -c \"from django.utils.crypto import get_random_secret_key; print(get_random_secret_key())\""
)

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = int(os.environ.get("DEBUG", "0"))
Expand All @@ -39,7 +58,6 @@
# Example: "10.0.0.0/8,192.168.1.0/24,172.16.0.5"
_webhook_allowed_ips_raw = os.environ.get("WEBHOOK_ALLOWED_IPS", "")
WEBHOOK_ALLOWED_IPS = []
_logger = logging.getLogger("plane")
for _cidr in _webhook_allowed_ips_raw.split(","):
_cidr = _cidr.strip()
if not _cidr:
Expand Down
34 changes: 30 additions & 4 deletions deployments/aio/community/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ print_header(){
echo " SITE_ADDRESS (default: ':80')"
echo " FILE_SIZE_LIMIT (default: 5242880)"
echo " APP_PROTOCOL (http or https)"
echo " SECRET_KEY (default: 60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5)"
echo " LIVE_SERVER_SECRET_KEY (default: htbqvBJAgpm9bzvf3r4urJer0ENReatceh)"
echo " SECRET_KEY (auto-generated on first boot if not set)"
echo " LIVE_SERVER_SECRET_KEY (auto-generated on first boot if not set)"
echo ""
echo ""
}
Expand Down Expand Up @@ -145,9 +145,35 @@ update_env_file(){
update_env_value "USE_MINIO" "0"

# Optional environment variables
update_env_value "SECRET_KEY" "${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}"
# SECRET_KEY: if absent or set to a known placeholder/insecure value, preserve whatever
# is already stored in plane.env (survives restarts), or generate a fresh random value on
# first boot. Never write a publicly-known or placeholder value into plane.env.
local _insecure_sk="60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5"
local _placeholder_sk="change-this-key-on-deployment"
if [ -z "$SECRET_KEY" ] || [ "$SECRET_KEY" = "$_insecure_sk" ] || [ "$SECRET_KEY" = "$_placeholder_sk" ]; then
local _stored_sk
_stored_sk=$(grep "^SECRET_KEY=" plane.env 2>/dev/null | cut -d'=' -f2-)
if [ -n "$_stored_sk" ] && [ "$_stored_sk" != "$_insecure_sk" ] && [ "$_stored_sk" != "$_placeholder_sk" ]; then
SECRET_KEY="$_stored_sk"
else
SECRET_KEY=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c50)
fi
fi
update_env_value "SECRET_KEY" "$SECRET_KEY"
update_env_value "FILE_SIZE_LIMIT" "${FILE_SIZE_LIMIT:-5242880}"
update_env_value "LIVE_SERVER_SECRET_KEY" "${LIVE_SERVER_SECRET_KEY:-htbqvBJAgpm9bzvf3r4urJer0ENReatceh}"
# LIVE_SERVER_SECRET_KEY: same first-boot generation strategy.
local _insecure_lssk="htbqvBJAgpm9bzvf3r4urJer0ENReatceh"
local _placeholder_lssk="change-this-key-on-deployment"
if [ -z "$LIVE_SERVER_SECRET_KEY" ] || [ "$LIVE_SERVER_SECRET_KEY" = "$_insecure_lssk" ] || [ "$LIVE_SERVER_SECRET_KEY" = "$_placeholder_lssk" ]; then
local _stored_lssk
_stored_lssk=$(grep "^LIVE_SERVER_SECRET_KEY=" plane.env 2>/dev/null | cut -d'=' -f2-)
if [ -n "$_stored_lssk" ] && [ "$_stored_lssk" != "$_insecure_lssk" ] && [ "$_stored_lssk" != "$_placeholder_lssk" ]; then
LIVE_SERVER_SECRET_KEY="$_stored_lssk"
else
LIVE_SERVER_SECRET_KEY=$(tr -dc 'a-zA-Z0-9' < /dev/urandom | head -c50)
fi
fi
update_env_value "LIVE_SERVER_SECRET_KEY" "$LIVE_SERVER_SECRET_KEY"

update_env_value "API_KEY_RATE_LIMIT" "${API_KEY_RATE_LIMIT:-60/minute}"

Expand Down
15 changes: 11 additions & 4 deletions deployments/aio/community/variables.env
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ REDIS_URL=
# RabbitMQ Settings
AMQP_URL=

# Secret Key
SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
# Secret Key — change this before deploying to production.
# Generate a secure value with: python3 -c "from django.utils.crypto import get_random_secret_key; print(get_random_secret_key())"
# or: openssl rand -hex 32
# The startup script auto-generates and persists a random key on first boot if the
# placeholder value below is left unchanged.
SECRET_KEY=change-this-key-on-deployment

# DATA STORE SETTINGS
USE_MINIO=0
Expand Down Expand Up @@ -54,8 +58,11 @@ API_KEY_RATE_LIMIT=60/minute
# where period is second/minute/hour/day.
AUTHENTICATION_RATE_LIMIT=10/minute

# Live Server Secret Key
LIVE_SERVER_SECRET_KEY=htbqvBJAgpm9bzvf3r4urJer0ENReatceh
# Live Server Secret Key — change this before deploying to production.
# Generate a secure value with: openssl rand -hex 32
# The startup script auto-generates and persists a random key on first boot if the
# placeholder value below is left unchanged.
LIVE_SERVER_SECRET_KEY=change-this-key-on-deployment

# Webhook IP allowlist — comma-separated IPs or CIDR ranges allowed as webhook targets
# even if they resolve to private networks (e.g. "10.0.0.0/8,192.168.1.0/24,172.16.0.5")
Expand Down
6 changes: 3 additions & 3 deletions deployments/cli/community/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ x-mq-env: &mq-env # RabbitMQ Settings

x-live-env: &live-env
API_BASE_URL: ${API_BASE_URL:-http://api:8000}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-2FiJk1U2aiVPEQtzLehYGlTSnTnrs7LW}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY}

x-app-env: &app-env
WEB_URL: ${WEB_URL:-http://localhost}
Expand All @@ -53,11 +53,11 @@ x-app-env: &app-env
GUNICORN_WORKERS: 1
USE_MINIO: ${USE_MINIO:-1}
DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane}
SECRET_KEY: ${SECRET_KEY:-60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5}
SECRET_KEY: ${SECRET_KEY}
AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane}
API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute}
MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-2FiJk1U2aiVPEQtzLehYGlTSnTnrs7LW}
LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY}
WEBHOOK_ALLOWED_IPS: ${WEBHOOK_ALLOWED_IPS:-}
WEBHOOK_ALLOWED_HOSTS: ${WEBHOOK_ALLOWED_HOSTS:-}

Expand Down
12 changes: 7 additions & 5 deletions deployments/cli/community/variables.env
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,10 @@ CERT_EMAIL=
CERT_ACME_DNS=


# Secret Key
SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
# Secret Key — change this before deploying to production.
# Generate a secure value with: python3 -c "from django.utils.crypto import get_random_secret_key; print(get_random_secret_key())"
# or: openssl rand -hex 32
SECRET_KEY=change-this-key-on-deployment

# DATA STORE SETTINGS
USE_MINIO=1
Expand Down Expand Up @@ -82,9 +84,9 @@ API_KEY_RATE_LIMIT=60/minute
# where period is second/minute/hour/day.
AUTHENTICATION_RATE_LIMIT=10/minute

# Live server environment variables
# WARNING: You must set a secure value for LIVE_SERVER_SECRET_KEY in production environments.
LIVE_SERVER_SECRET_KEY=
# Live server environment variables — change this before deploying to production.
# Generate a secure value with: openssl rand -hex 32
LIVE_SERVER_SECRET_KEY=change-this-key-on-deployment

# Webhook IP allowlist — comma-separated IPs or CIDR ranges allowed as webhook targets
# even if they resolve to private networks (e.g. "10.0.0.0/8,192.168.1.0/24,172.16.0.5")
Expand Down
Loading