Every CVE Search/ Get API key

CVE-2026-57147

praisonai-platform: default JWT signing secret 'dev-secret-change-me' enables token forgery

9.8 CriticalFix available

PraisonAI is a multi-agent teams system. Prior to 0.1.6, praisonai_platform/services/auth_service.py assigns the public dev-secret-change-me value to JWT_SECRET when PLATFORM_JWT_SECRET is unset, and its production guard does not run when PLATFORM_ENV is also unset because that setting defaults to dev. A remote unauthenticated attacker can mint an HS256 token with an arbitrary sub and email, and the platform's AuthService._verify_token() and get_current_user dependency accept the forged identity for protected API routes. This vulnerability is fixed in praisonai-platform 0.1.6.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
High
Integrity
High
Availability
High

Exploit likelihood

0.77%Up 0.3 points since Sep 15, 2026
90%50%10%1%

What each source reports

CVE List Score used 9.8

praisonai-platform: default JWT signing secret 'dev-secret-change-me' enables token forgery

PraisonAI is a multi-agent teams system. Prior to 0.1.6, praisonai_platform/services/auth_service.py assigns the public dev-secret-change-me value to JWT_SECRET when PLATFORM_JWT_SECRET is unset, and its production guard does not run when PLATFORM_ENV is also unset because that setting defaults to dev. A remote unauthenticated attacker can mint an HS256 token with an arbitrary sub and email, and the platform's AuthService._verify_token() and get_current_user dependency accept the forged identity for protected API routes. This vulnerability is fixed in praisonai-platform 0.1.6.

Record
CVE-2026-57147
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-798, CWE-1188
Updated
2026-11-02
EUVDEUVD-2026-78397 9.8

PraisonAI is a multi-agent teams system. Prior to 0.1.6, praisonai_platform/services/auth_service.py assigns the public dev-secret-change-me value to JWT_SECRET when PLATFORM_JWT_SECRET is unset, and its production guard does not run when PLATFORM_ENV is also unset because that setting defaults to dev. A remote unauthenticated attacker can mint an HS256 token with an arbitrary sub and email, and the platform's AuthService._verify_token() and get_current_user dependency accept the forged identity for protected API routes. This vulnerability is fixed in praisonai-platform 0.1.6.

Record
EUVD-2026-78397
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-cwj8-7gp2-ggcw 9.8

praisonai-platform: default JWT signing secret 'dev-secret-change-me' enables token forgery

praisonai-platform: default JWT signing secret dev-secret-change-me

Researcher: Kai Aizen — SnailSploit (@SnailSploit), Adversarial & Offensive Security Research Target: https://github.com/MervinPraison/PraisonAI


Package: praisonai-platform on PyPI Latest version (and version tested): 0.1.4, current as of 2026-06-01. File: praisonai_platform/services/auth_service.py (sha256 cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258). Weakness: CWE-798 Use of Hardcoded Credentials + CWE-1188 Insecure Default Initialization of Resource.


TL;DR

praisonai_platform/services/auth_service.py lines 25-37:

_DEFAULT_SECRET = "dev-secret-change-me"
JWT_SECRET = os.environ.get("PLATFORM_JWT_SECRET", _DEFAULT_SECRET)
JWT_ALGORITHM = "HS256"
JWT_TTL_SECONDS = int(os.environ.get("PLATFORM_JWT_TTL", str(30 * 24 * 3600)))

if JWT_SECRET == _DEFAULT_SECRET and os.environ.get("PLATFORM_ENV", "dev") != "dev":
    raise RuntimeError(
        "PLATFORM_JWT_SECRET must be set to a strong random value in production. "
        "Set PLATFORM_ENV=dev to suppress this check during development."
    )

The guard at line 33 is meant to catch the "deployed to production with the default secret" failure mode. But it only fires when both:

  • the operator left PLATFORM_JWT_SECRET unset (so JWT_SECRET is the default literal), and
  • the operator explicitly set PLATFORM_ENV to something other than "dev".

If the operator left both env vars unset — the most common mis-deploy — PLATFORM_ENV falls back to "dev", the second leg of the and evaluates False, and the guard does NOT fire. The server starts up signing every JWT with the public string 'dev-secret-change-me'.

The fix is to invert the polarity: refuse startup when the secret is the default regardless of PLATFORM_ENV, except when an explicit PLATFORM_ALLOW_DEV_SECRET=true (or equivalent) flag is set. That flips "default-allow" to "default-deny", which is what the line-33 comment implies the author wanted.

Root cause

   Expected behavior, reading line 33 of auth_service.py:
     "Good — the framework refuses to start in production with a
      default-string secret.  I'm safe by construction."

   Actual behavior:
     - PLATFORM_ENV defaults to 'dev' when unset.
     - The guard checks PLATFORM_ENV != 'dev', not PLATFORM_ENV == 'production'
       or "operator explicitly opted in to using the dev secret".
     - So the "deployed without setting any env var" config — typical
       for first-pip-install or quick-start docker — sits silently in
       dev mode with the public secret.

   Impact:
     A guard that requires the operator to EXPLICITLY signal
     "production" cannot catch operators who forgot to signal anything.
     The forgot-to-signal case is the one the guard was designed to
     catch.

Empirical verification

poc/poc.py imports the installed PyPI package (praisonai-platform==0.1.4) with both env vars unset:

[1] startup guard at auth_service.py:33 status
    Inputs:
      JWT_SECRET    = 'dev-secret-change-me'
      _DEFAULT_SECRET = 'dev-secret-change-me'
      PLATFORM_ENV  = 'dev'  (default 'dev')
    -> JWT_SECRET == _DEFAULT_SECRET: True
    -> PLATFORM_ENV != 'dev':         False
    -> guard fires?                   False

[2] module sha256: cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258
    JWT_ALGORITHM: 'HS256'

[3] forge a JWT signed with the live JWT_SECRET
    forged head: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

[4] jwt.decode(forged_token, JWT_SECRET) — same call as
    AuthService._verify_token at auth_service.py:139
    decoded.sub  = admin-user-id-attacker-chose
    decoded.email= [email protected]

[5] AuthService._verify_token(forged_token) (live method call)
    identity.id    = admin-user-id-attacker-chose
    identity.email = [email protected]

VERDICT: VULNERABLE
EXIT 0

Step [5] is the…

Record
GHSA-cwj8-7gp2-ggcw
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-798, CWE-1188
Updated
2026-11-02
NVD 9.8

PraisonAI is a multi-agent teams system. Prior to 0.1.6, praisonai_platform/services/auth_service.py assigns the public dev-secret-change-me value to JWT_SECRET when PLATFORM_JWT_SECRET is unset, and its production guard does not run when PLATFORM_ENV is also unset because that setting defaults to dev. A remote unauthenticated attacker can mint an HS256 token with an arbitrary sub and email, and the platform's AuthService._verify_token() and get_current_user dependency accept the forged identity for protected API routes. This vulnerability is fixed in praisonai-platform 0.1.6.

Record
CVE-2026-57147
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-798, CWE-1188
Updated
2026-11-02
OSV 9.8

praisonai-platform: default JWT signing secret 'dev-secret-change-me' enables token forgery

PraisonAI is a multi-agent teams system. Prior to 0.1.6, praisonai_platform/services/auth_service.py assigns the public dev-secret-change-me value to JWT_SECRET when PLATFORM_JWT_SECRET is unset, and its production guard does not run when PLATFORM_ENV is also unset because that setting defaults to dev. A remote unauthenticated attacker can mint an HS256 token with an arbitrary sub and email, and the platform's AuthService._verify_token() and get_current_user dependency accept the forged identity for protected API routes. This vulnerability is fixed in praisonai-platform 0.1.6.

Record
CVE-2026-57147
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-1188, CWE-798
Updated
2026-11-02
OSVGHSA-cwj8-7gp2-ggcw 9.8

praisonai-platform: default JWT signing secret 'dev-secret-change-me' enables token forgery

praisonai-platform: default JWT signing secret dev-secret-change-me

Researcher: Kai Aizen — SnailSploit (@SnailSploit), Adversarial & Offensive Security Research Target: https://github.com/MervinPraison/PraisonAI


Package: praisonai-platform on PyPI Latest version (and version tested): 0.1.4, current as of 2026-06-01. File: praisonai_platform/services/auth_service.py (sha256 cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258). Weakness: CWE-798 Use of Hardcoded Credentials + CWE-1188 Insecure Default Initialization of Resource.


TL;DR

praisonai_platform/services/auth_service.py lines 25-37:

_DEFAULT_SECRET = "dev-secret-change-me"
JWT_SECRET = os.environ.get("PLATFORM_JWT_SECRET", _DEFAULT_SECRET)
JWT_ALGORITHM = "HS256"
JWT_TTL_SECONDS = int(os.environ.get("PLATFORM_JWT_TTL", str(30 * 24 * 3600)))

if JWT_SECRET == _DEFAULT_SECRET and os.environ.get("PLATFORM_ENV", "dev") != "dev":
    raise RuntimeError(
        "PLATFORM_JWT_SECRET must be set to a strong random value in production. "
        "Set PLATFORM_ENV=dev to suppress this check during development."
    )

The guard at line 33 is meant to catch the "deployed to production with the default secret" failure mode. But it only fires when both:

  • the operator left PLATFORM_JWT_SECRET unset (so JWT_SECRET is the default literal), and
  • the operator explicitly set PLATFORM_ENV to something other than "dev".

If the operator left both env vars unset — the most common mis-deploy — PLATFORM_ENV falls back to "dev", the second leg of the and evaluates False, and the guard does NOT fire. The server starts up signing every JWT with the public string 'dev-secret-change-me'.

The fix is to invert the polarity: refuse startup when the secret is the default regardless of PLATFORM_ENV, except when an explicit PLATFORM_ALLOW_DEV_SECRET=true (or equivalent) flag is set. That flips "default-allow" to "default-deny", which is what the line-33 comment implies the author wanted.

Root cause

   Expected behavior, reading line 33 of auth_service.py:
     "Good — the framework refuses to start in production with a
      default-string secret.  I'm safe by construction."

   Actual behavior:
     - PLATFORM_ENV defaults to 'dev' when unset.
     - The guard checks PLATFORM_ENV != 'dev', not PLATFORM_ENV == 'production'
       or "operator explicitly opted in to using the dev secret".
     - So the "deployed without setting any env var" config — typical
       for first-pip-install or quick-start docker — sits silently in
       dev mode with the public secret.

   Impact:
     A guard that requires the operator to EXPLICITLY signal
     "production" cannot catch operators who forgot to signal anything.
     The forgot-to-signal case is the one the guard was designed to
     catch.

Empirical verification

poc/poc.py imports the installed PyPI package (praisonai-platform==0.1.4) with both env vars unset:

[1] startup guard at auth_service.py:33 status
    Inputs:
      JWT_SECRET    = 'dev-secret-change-me'
      _DEFAULT_SECRET = 'dev-secret-change-me'
      PLATFORM_ENV  = 'dev'  (default 'dev')
    -> JWT_SECRET == _DEFAULT_SECRET: True
    -> PLATFORM_ENV != 'dev':         False
    -> guard fires?                   False

[2] module sha256: cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258
    JWT_ALGORITHM: 'HS256'

[3] forge a JWT signed with the live JWT_SECRET
    forged head: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

[4] jwt.decode(forged_token, JWT_SECRET) — same call as
    AuthService._verify_token at auth_service.py:139
    decoded.sub  = admin-user-id-attacker-chose
    decoded.email= [email protected]

[5] AuthService._verify_token(forged_token) (live method call)
    identity.id    = admin-user-id-attacker-chose
    identity.email = [email protected]

VERDICT: VULNERABLE
EXIT 0

Step [5] is the…

Record
GHSA-cwj8-7gp2-ggcw
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Weakness
CWE-1188, CWE-798
Updated
2026-11-02
OSVPYSEC-2026-3524 9.8

praisonai-platform: default JWT signing secret 'dev-secret-change-me' enables token forgery

praisonai-platform: default JWT signing secret dev-secret-change-me

Researcher: Kai Aizen — SnailSploit (@SnailSploit), Adversarial & Offensive Security Research Target: https://github.com/MervinPraison/PraisonAI


Package: praisonai-platform on PyPI Latest version (and version tested): 0.1.4, current as of 2026-06-01. File: praisonai_platform/services/auth_service.py (sha256 cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258). Weakness: CWE-798 Use of Hardcoded Credentials + CWE-1188 Insecure Default Initialization of Resource.


TL;DR

praisonai_platform/services/auth_service.py lines 25-37:

_DEFAULT_SECRET = "dev-secret-change-me"
JWT_SECRET = os.environ.get("PLATFORM_JWT_SECRET", _DEFAULT_SECRET)
JWT_ALGORITHM = "HS256"
JWT_TTL_SECONDS = int(os.environ.get("PLATFORM_JWT_TTL", str(30 * 24 * 3600)))

if JWT_SECRET == _DEFAULT_SECRET and os.environ.get("PLATFORM_ENV", "dev") != "dev":
    raise RuntimeError(
        "PLATFORM_JWT_SECRET must be set to a strong random value in production. "
        "Set PLATFORM_ENV=dev to suppress this check during development."
    )

The guard at line 33 is meant to catch the "deployed to production with the default secret" failure mode. But it only fires when both:

  • the operator left PLATFORM_JWT_SECRET unset (so JWT_SECRET is the default literal), and
  • the operator explicitly set PLATFORM_ENV to something other than "dev".

If the operator left both env vars unset — the most common mis-deploy — PLATFORM_ENV falls back to "dev", the second leg of the and evaluates False, and the guard does NOT fire. The server starts up signing every JWT with the public string 'dev-secret-change-me'.

The fix is to invert the polarity: refuse startup when the secret is the default regardless of PLATFORM_ENV, except when an explicit PLATFORM_ALLOW_DEV_SECRET=true (or equivalent) flag is set. That flips "default-allow" to "default-deny", which is what the line-33 comment implies the author wanted.

Root cause

   Expected behavior, reading line 33 of auth_service.py:
     "Good — the framework refuses to start in production with a
      default-string secret.  I'm safe by construction."

   Actual behavior:
     - PLATFORM_ENV defaults to 'dev' when unset.
     - The guard checks PLATFORM_ENV != 'dev', not PLATFORM_ENV == 'production'
       or "operator explicitly opted in to using the dev secret".
     - So the "deployed without setting any env var" config — typical
       for first-pip-install or quick-start docker — sits silently in
       dev mode with the public secret.

   Impact:
     A guard that requires the operator to EXPLICITLY signal
     "production" cannot catch operators who forgot to signal anything.
     The forgot-to-signal case is the one the guard was designed to
     catch.

Empirical verification

poc/poc.py imports the installed PyPI package (praisonai-platform==0.1.4) with both env vars unset:

[1] startup guard at auth_service.py:33 status
    Inputs:
      JWT_SECRET    = 'dev-secret-change-me'
      _DEFAULT_SECRET = 'dev-secret-change-me'
      PLATFORM_ENV  = 'dev'  (default 'dev')
    -> JWT_SECRET == _DEFAULT_SECRET: True
    -> PLATFORM_ENV != 'dev':         False
    -> guard fires?                   False

[2] module sha256: cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258
    JWT_ALGORITHM: 'HS256'

[3] forge a JWT signed with the live JWT_SECRET
    forged head: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

[4] jwt.decode(forged_token, JWT_SECRET) — same call as
    AuthService._verify_token at auth_service.py:139
    decoded.sub  = admin-user-id-attacker-chose
    decoded.email= [email protected]

[5] AuthService._verify_token(forged_token) (live method call)
    identity.id    = admin-user-id-attacker-chose
    identity.email = [email protected]

VERDICT: VULNERABLE
EXIT 0

Step [5] is the…

Record
PYSEC-2026-3524
CVSS 3.1
9.8 CriticalCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
praisonai-platform
PyPI
through 0.1.4
0.1.6
praisonai-platform
PyPI
before 0.1.6, plus listed versions
0.1.00.1.10.1.20.1.30.1.4
0.1.6

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-57147 is a critical vulnerability (CVSS 9.8) in Mervinpraison Praisonai, published June 18, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.77%, the 55th percentile. Fixed in praisonai-platform 0.1.6.

References

Show 4 moreShow less
This page doesn't list everything

Left out here: the rest of 3 source descriptions. The JSON record has them.

MoveEnter Open