CWE-613
Allowed-with-ReviewInsufficient Session Expiration
Abstraction: Base · Status: Incomplete
According to WASC, "Insufficient Session Expiration is when a web site permits an attacker to reuse old session credentials or session IDs for authorization."
1091 vulnerabilities reference this CWE, most recent first.
GHSA-63V5-26VQ-M4VM
Vulnerability from github – Published: 2026-01-26 21:30 – Updated: 2026-03-06 00:31A flaw was found in Keycloak's SAML brokering functionality. When Keycloak is configured as a client in a Security Assertion Markup Language (SAML) setup, it fails to validate the NotOnOrAfter timestamp within the SubjectConfirmationData. This allows an attacker to delay the expiration of SAML responses, potentially extending the time a response is considered valid and leading to unexpected session durations or resource consumption.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.keycloak:keycloak-services"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "26.5.2"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-1190"
],
"database_specific": {
"cwe_ids": [
"CWE-112",
"CWE-347",
"CWE-613"
],
"github_reviewed": true,
"github_reviewed_at": "2026-01-27T21:56:13Z",
"nvd_published_at": "2026-01-26T20:16:09Z",
"severity": "LOW"
},
"details": "A flaw was found in Keycloak\u0027s SAML brokering functionality. When Keycloak is configured as a client in a Security Assertion Markup Language (SAML) setup, it fails to validate the `NotOnOrAfter` timestamp within the `SubjectConfirmationData`. This allows an attacker to delay the expiration of SAML responses, potentially extending the time a response is considered valid and leading to unexpected session durations or resource consumption.",
"id": "GHSA-63v5-26vq-m4vm",
"modified": "2026-03-06T00:31:28Z",
"published": "2026-01-26T21:30:36Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-1190"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/issues/45646"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:3947"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2026:3948"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2026-1190"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2430835"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Keycloak\u0027s missing timestamp validation allows attackers to extend SAML response validity periods"
}
GHSA-64W3-5Q9M-68XF
Vulnerability from github – Published: 2025-10-23 15:30 – Updated: 2026-02-17 17:20A flaw was found in Keycloak. Keycloak does not immediately enforce the disabling of the "Remember Me" realm setting on existing user sessions. Sessions created while "Remember Me" was active retain their extended session lifetime until they expire, overriding the administrator's recent security configuration change. This is a logic flaw in session management increases the potential window for successful session hijacking or unauthorized long-term access persistence. The flaw lies in the session expiration logic relying on the session-local "remember-me" flag without validating the current realm-level configuration.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "org.keycloak:keycloak-services"
},
"ranges": [
{
"events": [
{
"introduced": "26.3.0"
},
{
"fixed": "26.4.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "org.keycloak:keycloak-services"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "26.2.11"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2025-11429"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": true,
"github_reviewed_at": "2025-10-23T19:24:48Z",
"nvd_published_at": "2025-10-23T14:15:35Z",
"severity": "MODERATE"
},
"details": "A flaw was found in Keycloak. Keycloak does not immediately enforce the disabling of the \"Remember Me\" realm setting on existing user sessions. Sessions created while \"Remember Me\" was active retain their extended session lifetime until they expire, overriding the administrator\u0027s recent security configuration change. This is a logic flaw in session management increases the potential window for successful session hijacking or unauthorized long-term access persistence. The flaw lies in the session expiration logic relying on the session-local \"remember-me\" flag without validating the current realm-level configuration.",
"id": "GHSA-64w3-5q9m-68xf",
"modified": "2026-02-17T17:20:04Z",
"published": "2025-10-23T15:30:34Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-11429"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/issues/43328"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/commit/a34094100716b7c69ae38eaed6678ab4344d0a1d"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/commit/a752492843e21c3ab06090616692e53001864158"
},
{
"type": "WEB",
"url": "https://github.com/keycloak/keycloak/commit/bda0e2a67c8cf41d1b3d9010e6dfcddaf79bf59b"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2025:22088"
},
{
"type": "WEB",
"url": "https://access.redhat.com/errata/RHSA-2025:22089"
},
{
"type": "WEB",
"url": "https://access.redhat.com/security/cve/CVE-2025-11429"
},
{
"type": "WEB",
"url": "https://bugzilla.redhat.com/show_bug.cgi?id=2402148"
},
{
"type": "PACKAGE",
"url": "https://github.com/keycloak/keycloak"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "Keycloak does not invalidate sessions when \"Remember Me\" is disabled"
}
GHSA-65C7-88XP-PCV7
Vulnerability from github – Published: 2022-05-24 16:49 – Updated: 2022-10-25 19:00Prima Systems FlexAir devices have an Insufficient Session-ID Length.
{
"affected": [],
"aliases": [
"CVE-2019-7280"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-07-01T19:15:00Z",
"severity": "HIGH"
},
"details": "Prima Systems FlexAir devices have an Insufficient Session-ID Length.",
"id": "GHSA-65c7-88xp-pcv7",
"modified": "2022-10-25T19:00:32Z",
"published": "2022-05-24T16:49:11Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-7280"
},
{
"type": "WEB",
"url": "https://applied-risk.com/labs/advisories"
},
{
"type": "WEB",
"url": "https://www.applied-risk.com/resources/ar-2019-007"
},
{
"type": "WEB",
"url": "https://www.us-cert.gov/ics/advisories/icsa-19-211-02"
}
],
"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-65MJ-98XR-M8MH
Vulnerability from github – Published: 2023-05-02 21:31 – Updated: 2024-04-04 03:46An issue in the time-based authentication mechanism of Aigital Aigital Wireless-N Repeater Mini_Router v0.131229 allows attackers to bypass login by connecting to the web app after a successful attempt by a legitimate user.
{
"affected": [],
"aliases": [
"CVE-2023-30403"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-05-02T20:15:10Z",
"severity": "HIGH"
},
"details": "An issue in the time-based authentication mechanism of Aigital Aigital Wireless-N Repeater Mini_Router v0.131229 allows attackers to bypass login by connecting to the web app after a successful attempt by a legitimate user.",
"id": "GHSA-65mj-98xr-m8mh",
"modified": "2024-04-04T03:46:45Z",
"published": "2023-05-02T21:31:48Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-30403"
},
{
"type": "WEB",
"url": "https://dl.packetstormsecurity.net/2305-exploits/aigitalwnr-bypass.txt"
},
{
"type": "WEB",
"url": "https://mandomat.github.io/2023-04-13-testing-a-cheap-wifi-repeater"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-65V7-8599-57VR
Vulnerability from github – Published: 2025-10-01 18:30 – Updated: 2025-10-01 18:30IBM Transformation Extender Advanced 10.0.1
does not invalidate session after logout which could allow an authenticated user to impersonate another user on the system.
{
"affected": [],
"aliases": [
"CVE-2023-49881"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-10-01T17:15:37Z",
"severity": "MODERATE"
},
"details": "IBM Transformation Extender Advanced 10.0.1 \n\ndoes not invalidate session after logout which could allow an authenticated user to impersonate another user on the system.",
"id": "GHSA-65v7-8599-57vr",
"modified": "2025-10-01T18:30:38Z",
"published": "2025-10-01T18:30:38Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-49881"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/7246882"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-666M-X6MQ-3HP8
Vulnerability from github – Published: 2023-06-05 03:31 – Updated: 2024-04-04 04:31IBM Security Guardium 11.5 could allow a user to take over another user's session due to insufficient session expiration. IBM X-Force ID: 243657.
{
"affected": [],
"aliases": [
"CVE-2023-0041"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-06-05T01:15:45Z",
"severity": "HIGH"
},
"details": "IBM Security Guardium 11.5 could allow a user to take over another user\u0027s session due to insufficient session expiration. IBM X-Force ID: 243657.",
"id": "GHSA-666m-x6mq-3hp8",
"modified": "2024-04-04T04:31:33Z",
"published": "2023-06-05T03:31:46Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-0041"
},
{
"type": "WEB",
"url": "https://exchange.xforce.ibmcloud.com/vulnerabilities/243657"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/7000021"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-66C7-2F58-RWHJ
Vulnerability from github – Published: 2026-08-06 09:30 – Updated: 2026-08-06 09:30Unused authorization codes issued to deleted users are not being properly invalidated or removed from the system. This allows for the persistence of these codes, enabling them to be potentially reused.
If an attacker possesses both the authorization code and the associated client credentials (client ID and client secret), they can leverage these unused codes to obtain access tokens on behalf of users who have already been deleted. This may lead to unauthorized access to sensitive resources and services, contingent on the scopes originally authorized for the compromised authorization code.
{
"affected": [],
"aliases": [
"CVE-2024-8995"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-08-06T08:16:27Z",
"severity": "MODERATE"
},
"details": "Unused authorization codes issued to deleted users are not being properly invalidated or removed from the system. This allows for the persistence of these codes, enabling them to be potentially reused.\n\nIf an attacker possesses both the authorization code and the associated client credentials (client ID and client secret), they can leverage these unused codes to obtain access tokens on behalf of users who have already been deleted. This may lead to unauthorized access to sensitive resources and services, contingent on the scopes originally authorized for the compromised authorization code.",
"id": "GHSA-66c7-2f58-rwhj",
"modified": "2026-08-06T09:30:30Z",
"published": "2026-08-06T09:30:30Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-8995"
},
{
"type": "WEB",
"url": "https://security.docs.wso2.com/en/latest/security-announcements/security-advisories/2026/WSO2-2024-2753"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-66HX-CHF7-3332
Vulnerability from github – Published: 2026-04-14 23:38 – Updated: 2026-04-24 20:42Summary
pyLoad caches role and permission in the session at login and continues to authorize requests using these cached values, even after an admin changes the user's role/permissions in the database.
As a result, an already logged-in user can keep old (revoked) privileges until logout/session expiry, enabling continued privileged actions.
This is a core authorization/session-consistency issue and is not resolved by toggling an optional security feature.
Details
The WebUI auth flow stores authorization state in session:
src/pyload/webui/app/helpers.py:187-200set_session(...)writes:"role": user_info["role"]"perms": user_info["permission"]
Authorization checks later trust cached session values:
src/pyload/webui/app/helpers.py:134-151parse_permissions(...)readssession.get("role")/session.get("perms")src/pyload/webui/app/helpers.py:225-230is_authenticated(...)only verifiesauthenticatedandapi.user_exists(user)(existence), not fresh role/permissionsrc/pyload/webui/app/helpers.py:267-275login_required(...)usesparse_permissions(s)for allow/deny decisionssrc/pyload/webui/app/helpers.py:356-365- API session auth path also trusts
s["role"]ands["perms"]
Role/permission updates are written to DB but active sessions are not invalidated/refreshed:
src/pyload/webui/app/blueprints/json_blueprint.py:389-434update_users(...)callsapi.set_user_permission(...)and returnssrc/pyload/core/api/__init__.py:1643-1645set_user_permission(...)updates DB role/permission only
Default exposure window is long:
src/pyload/core/config/default.cfg:47session_lifetime = 44640minutes (~31 days)
Therefore, privilege revocation is not enforced immediately for active sessions.
Note on duplicates: - This appears distinct from CVE-2023-0227 (session validity after user deletion) because this report is about stale authorization after role/permission changes while the user still exists.
PoC
#!/usr/bin/env python3
"""
Repro: stale session privilege after role/permission changes.
This PoC is source-based and leaves no persistent state.
It validates that:
1) Role/permission are cached into session at login.
2) Authorization checks read role/permission from session, not fresh DB values.
3) User updates write DB permission/role without invalidating active sessions.
4) Default session lifetime is long, increasing stale-privilege exposure window.
"""
from __future__ import annotations
import pathlib
import re
from typing import Iterable
ROOT = pathlib.Path(__file__).resolve().parent / "pyload" / "src" / "pyload"
def read(rel: str) -> str:
return (ROOT / rel).read_text(encoding="utf-8")
def has_any(text: str, patterns: Iterable[str]) -> bool:
return all(re.search(p, text, re.MULTILINE) for p in patterns)
def main() -> None:
helpers = read("webui/app/helpers.py")
json_blueprint = read("webui/app/blueprints/json_blueprint.py")
api_init = read("core/api/__init__.py")
default_cfg = (ROOT / "core/config/default.cfg").read_text(encoding="utf-8")
checks = {
"set_session_caches_role_perms": has_any(
helpers,
[
r'def\\s+set_session\\(',
r'"role"\\s*:\\s*user_info\\["role"\\]',
r'"perms"\\s*:\\s*user_info\\["permission"\\]',
],
),
"is_authenticated_only_checks_user_exists": has_any(
helpers,
[
r'def\\s+is_authenticated\\(',
r'api\\s*=\\s*flask\\.current_app\\.config\\["PYLOAD_API"\\]',
r'return\\s+authenticated\\s+and\\s+api\\.user_exists\\(user\\)',
],
),
"parse_permissions_reads_session_cache": has_any(
helpers,
[
r'def\\s+parse_permissions\\(',
r'session\\.get\\("role"\\)\\s*==\\s*Role\\.ADMIN',
r'session\\.get\\("perms"\\)',
],
),
"login_required_uses_parse_permissions_session": has_any(
helpers,
[
r'def\\s+login_required\\(',
r'if\\s+is_authenticated\\(s\\):',
r'perms\\s*=\\s*parse_permissions\\(s\\)',
],
),
"api_session_auth_uses_cached_role_perms": has_any(
helpers,
[
r'if\\s+is_authenticated\\(s\\):',
r'"role"\\s*:\\s*s\\["role"\\]',
r'"permission"\\s*:\\s*s\\["perms"\\]',
],
),
"update_users_changes_db_without_session_invalidation": has_any(
json_blueprint,
[
r'def\\s+update_users\\(',
r'api\\.set_user_permission\\(name,\\s*data\\["permission"\\],\\s*data\\["role"\\]\\)',
r'return\\s+jsonify\\(True\\)',
],
),
"set_user_permission_only_updates_db": has_any(
api_init,
[
r'def\\s+set_user_permission\\(',
r'self\\.pyload\\.db\\.set_permission\\(user,\\s*permission\\)',
r'self\\.pyload\\.db\\.set_role\\(user,\\s*role\\)',
],
),
"default_session_lifetime_long": re.search(
r'session_lifetime\\s*:\\s*"Session lifetime \\(minutes\\)"\\s*=\\s*44640',
default_cfg,
re.MULTILINE,
)
is not None,
}
for name, ok in checks.items():
print(f"{name}={ok}")
stale_privilege_repro_success = all(checks.values())
print(f"stale_privilege_repro_success={stale_privilege_repro_success}")
# Cleanup: this PoC creates/modifies no runtime/data files.
print("cleanup_done=True")
if __name__ == "__main__":
main()
set_session_caches_role_perms=True
is_authenticated_only_checks_user_exists=True
parse_permissions_reads_session_cache=True
login_required_uses_parse_permissions_session=True
api_session_auth_uses_cached_role_perms=True
update_users_changes_db_without_session_invalidation=True
set_user_permission_only_updates_db=True
default_session_lifetime_long=True
stale_privilege_repro_success=True
cleanup_done=True
Impact
- Privilege revocation is not immediate for active sessions.
- A user can continue using stale, previously granted privileges (including admin) after downgrade/restriction.
- This can allow continued access to privileged WebUI/API actions until session expiry or manual logout/session reset.
{
"affected": [
{
"package": {
"ecosystem": "PyPI",
"name": "pyload-ng"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"last_affected": "0.5.0b3.dev97"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-41133"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": true,
"github_reviewed_at": "2026-04-14T23:38:35Z",
"nvd_published_at": "2026-04-22T00:16:29Z",
"severity": "HIGH"
},
"details": "### Summary\npyLoad caches `role` and `permission` in the session at login and continues to authorize requests using these cached values, even after an admin changes the user\u0027s role/permissions in the database.\n\nAs a result, an already logged-in user can keep old (revoked) privileges until logout/session expiry, enabling continued privileged actions.\n\nThis is a core authorization/session-consistency issue and is not resolved by toggling an optional security feature.\n\n### Details\nThe WebUI auth flow stores authorization state in session:\n\n- `src/pyload/webui/app/helpers.py:187-200`\n - `set_session(...)` writes:\n - `\"role\": user_info[\"role\"]`\n - `\"perms\": user_info[\"permission\"]`\n\nAuthorization checks later trust cached session values:\n\n- `src/pyload/webui/app/helpers.py:134-151`\n - `parse_permissions(...)` reads `session.get(\"role\")` / `session.get(\"perms\")`\n- `src/pyload/webui/app/helpers.py:225-230`\n - `is_authenticated(...)` only verifies `authenticated` and `api.user_exists(user)` (existence), not fresh role/permission\n- `src/pyload/webui/app/helpers.py:267-275`\n - `login_required(...)` uses `parse_permissions(s)` for allow/deny decisions\n- `src/pyload/webui/app/helpers.py:356-365`\n - API session auth path also trusts `s[\"role\"]` and `s[\"perms\"]`\n\nRole/permission updates are written to DB but active sessions are not invalidated/refreshed:\n\n- `src/pyload/webui/app/blueprints/json_blueprint.py:389-434`\n - `update_users(...)` calls `api.set_user_permission(...)` and returns\n- `src/pyload/core/api/__init__.py:1643-1645`\n - `set_user_permission(...)` updates DB role/permission only\n\nDefault exposure window is long:\n\n- `src/pyload/core/config/default.cfg:47`\n - `session_lifetime = 44640` minutes (~31 days)\n\nTherefore, privilege revocation is not enforced immediately for active sessions.\n\nNote on duplicates:\n- This appears distinct from CVE-2023-0227 (session validity after **user deletion**) because this report is about stale authorization after **role/permission changes** while the user still exists.\n\n### PoC\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nRepro: stale session privilege after role/permission changes.\n\nThis PoC is source-based and leaves no persistent state.\nIt validates that:\n1) Role/permission are cached into session at login.\n2) Authorization checks read role/permission from session, not fresh DB values.\n3) User updates write DB permission/role without invalidating active sessions.\n4) Default session lifetime is long, increasing stale-privilege exposure window.\n\"\"\"\n\nfrom __future__ import annotations\n\nimport pathlib\nimport re\nfrom typing import Iterable\n\n\nROOT = pathlib.Path(__file__).resolve().parent / \"pyload\" / \"src\" / \"pyload\"\n\n\ndef read(rel: str) -\u003e str:\n return (ROOT / rel).read_text(encoding=\"utf-8\")\n\n\ndef has_any(text: str, patterns: Iterable[str]) -\u003e bool:\n return all(re.search(p, text, re.MULTILINE) for p in patterns)\n\n\ndef main() -\u003e None:\n helpers = read(\"webui/app/helpers.py\")\n json_blueprint = read(\"webui/app/blueprints/json_blueprint.py\")\n api_init = read(\"core/api/__init__.py\")\n default_cfg = (ROOT / \"core/config/default.cfg\").read_text(encoding=\"utf-8\")\n\n checks = {\n \"set_session_caches_role_perms\": has_any(\n helpers,\n [\n r\u0027def\\\\s+set_session\\\\(\u0027,\n r\u0027\"role\"\\\\s*:\\\\s*user_info\\\\[\"role\"\\\\]\u0027,\n r\u0027\"perms\"\\\\s*:\\\\s*user_info\\\\[\"permission\"\\\\]\u0027,\n ],\n ),\n \"is_authenticated_only_checks_user_exists\": has_any(\n helpers,\n [\n r\u0027def\\\\s+is_authenticated\\\\(\u0027,\n r\u0027api\\\\s*=\\\\s*flask\\\\.current_app\\\\.config\\\\[\"PYLOAD_API\"\\\\]\u0027,\n r\u0027return\\\\s+authenticated\\\\s+and\\\\s+api\\\\.user_exists\\\\(user\\\\)\u0027,\n ],\n ),\n \"parse_permissions_reads_session_cache\": has_any(\n helpers,\n [\n r\u0027def\\\\s+parse_permissions\\\\(\u0027,\n r\u0027session\\\\.get\\\\(\"role\"\\\\)\\\\s*==\\\\s*Role\\\\.ADMIN\u0027,\n r\u0027session\\\\.get\\\\(\"perms\"\\\\)\u0027,\n ],\n ),\n \"login_required_uses_parse_permissions_session\": has_any(\n helpers,\n [\n r\u0027def\\\\s+login_required\\\\(\u0027,\n r\u0027if\\\\s+is_authenticated\\\\(s\\\\):\u0027,\n r\u0027perms\\\\s*=\\\\s*parse_permissions\\\\(s\\\\)\u0027,\n ],\n ),\n \"api_session_auth_uses_cached_role_perms\": has_any(\n helpers,\n [\n r\u0027if\\\\s+is_authenticated\\\\(s\\\\):\u0027,\n r\u0027\"role\"\\\\s*:\\\\s*s\\\\[\"role\"\\\\]\u0027,\n r\u0027\"permission\"\\\\s*:\\\\s*s\\\\[\"perms\"\\\\]\u0027,\n ],\n ),\n \"update_users_changes_db_without_session_invalidation\": has_any(\n json_blueprint,\n [\n r\u0027def\\\\s+update_users\\\\(\u0027,\n r\u0027api\\\\.set_user_permission\\\\(name,\\\\s*data\\\\[\"permission\"\\\\],\\\\s*data\\\\[\"role\"\\\\]\\\\)\u0027,\n r\u0027return\\\\s+jsonify\\\\(True\\\\)\u0027,\n ],\n ),\n \"set_user_permission_only_updates_db\": has_any(\n api_init,\n [\n r\u0027def\\\\s+set_user_permission\\\\(\u0027,\n r\u0027self\\\\.pyload\\\\.db\\\\.set_permission\\\\(user,\\\\s*permission\\\\)\u0027,\n r\u0027self\\\\.pyload\\\\.db\\\\.set_role\\\\(user,\\\\s*role\\\\)\u0027,\n ],\n ),\n \"default_session_lifetime_long\": re.search(\n r\u0027session_lifetime\\\\s*:\\\\s*\"Session lifetime \\\\(minutes\\\\)\"\\\\s*=\\\\s*44640\u0027,\n default_cfg,\n re.MULTILINE,\n )\n is not None,\n }\n\n for name, ok in checks.items():\n print(f\"{name}={ok}\")\n\n stale_privilege_repro_success = all(checks.values())\n print(f\"stale_privilege_repro_success={stale_privilege_repro_success}\")\n\n # Cleanup: this PoC creates/modifies no runtime/data files.\n print(\"cleanup_done=True\")\n\n\nif __name__ == \"__main__\":\n main()\n```\n\n```text\nset_session_caches_role_perms=True\nis_authenticated_only_checks_user_exists=True\nparse_permissions_reads_session_cache=True\nlogin_required_uses_parse_permissions_session=True\napi_session_auth_uses_cached_role_perms=True\nupdate_users_changes_db_without_session_invalidation=True\nset_user_permission_only_updates_db=True\ndefault_session_lifetime_long=True\nstale_privilege_repro_success=True\ncleanup_done=True\n```\n\n### Impact\n- Privilege revocation is not immediate for active sessions.\n- A user can continue using stale, previously granted privileges (including admin) after downgrade/restriction.\n- This can allow continued access to privileged WebUI/API actions until session expiry or manual logout/session reset.",
"id": "GHSA-66hx-chf7-3332",
"modified": "2026-04-24T20:42:27Z",
"published": "2026-04-14T23:38:35Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/pyload/pyload/security/advisories/GHSA-66hx-chf7-3332"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-41133"
},
{
"type": "WEB",
"url": "https://github.com/pyload/pyload/commit/e95804fb0d06cbb07d2ba380fc494d9ff89b68c1"
},
{
"type": "PACKAGE",
"url": "https://github.com/pyload/pyload"
}
],
"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"
}
],
"summary": "pyLoad has Stale Session Privilege After Role/Permission Change (Privilege Revocation Bypass)"
}
GHSA-6826-48WR-PH83
Vulnerability from github – Published: 2026-07-30 21:31 – Updated: 2026-07-30 21:31IBM Operations Analytics - Log Analysis 1.3.5.0, 1.3.5.1, 1.3.5.2, 1.3.5.3, 1.3.6.0, 1.3.6.1, 1.3.7.0, 1.3.7.1, 1.3.7.2, and 1.3.8.0, 1.3.8.1, 1.3.8.2, 1.3.8.3, 1.3.8.4 does not invalidate session after a password chance which could allow an authenticated user to impersonate another user on the system.
{
"affected": [],
"aliases": [
"CVE-2024-40683"
],
"database_specific": {
"cwe_ids": [
"CWE-613"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-07-30T19:16:57Z",
"severity": "MODERATE"
},
"details": "IBM Operations Analytics - Log Analysis 1.3.5.0, 1.3.5.1, 1.3.5.2, 1.3.5.3, 1.3.6.0, 1.3.6.1, 1.3.7.0, 1.3.7.1, 1.3.7.2, and 1.3.8.0, 1.3.8.1, 1.3.8.2, 1.3.8.3, 1.3.8.4 does not invalidate session after a password chance which could allow an authenticated user to impersonate another user on the system.",
"id": "GHSA-6826-48wr-ph83",
"modified": "2026-07-30T21:31:47Z",
"published": "2026-07-30T21:31:47Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-40683"
},
{
"type": "WEB",
"url": "https://www.ibm.com/support/pages/node/7279877"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
}
]
}
GHSA-687G-22H4-J4W4
Vulnerability from github – Published: 2026-10-08 22:02 – Updated: 2026-10-08 22:02Summary
createVerifier({ clockTolerance: Infinity }) silently bypasses both exp (expiry) AND nbf (not-before) validation. Any expired or not-yet-active token is accepted as valid. The same primitive also corrupts the verifier's internal cache so cached entries inherit infinite validity — they remain valid past a later developer-removed Infinity config until LRU eviction.
Vulnerable code
src/verifier.js:531-533 — option validation only rejects negative values, not Infinity:
if (clockTolerance && (typeof clockTolerance !== 'number' || clockTolerance < 0)) {
throw new TokenError(TokenError.codes.invalidOption, 'The clockTolerance option must be a positive number.')
}
Infinity passes (it's a number, not less than 0, truthy).
src/verifier.js:583-602 — clockTolerance flows into the date-claim validators:
if (!ignoreNotBefore) {
validators.push({ ..., modifier: -clockTolerance }) // → -Infinity
}
if (!ignoreExpiration) {
validators.push({ ..., modifier: +clockTolerance }) // → Infinity
}
src/verifier.js:198-205 — applies modifier additively, producing always-pass comparisons:
function validateClaimDateValue(value, modifier, now, greater, errorCode, errorVerb) {
const adjusted = value * 1000 + (modifier || 0) // → ±Infinity
const valid = greater ? now >= adjusted : now <= adjusted // → always true
...
}
Empirical PoC
const { createSigner, createVerifier } = require('fast-jwt')
const secret = 'test-secret-with-enough-length-to-pass'
const sign = createSigner({ key: secret, algorithm: 'HS256' })
const expiredToken = sign({
sub: 'alice',
iat: Math.floor(Date.now()/1000) - 3600,
exp: Math.floor(Date.now()/1000) - 1800, // expired 30 min ago
})
const v1 = createVerifier({ key: secret })
try { v1(expiredToken) } catch (e) { console.log('baseline rejects:', e.message) }
// → "The token has expired at ..."
const v2 = createVerifier({ key: secret, clockTolerance: Infinity })
console.log('bypass:', v2(expiredToken))
// → { sub: 'alice', iat: ..., exp: ... } ← expired token accepted as valid
// Not-yet-active token (nbf in 1 day) — same bypass
const futureToken = sign({
sub: 'bob',
iat: Math.floor(Date.now()/1000),
nbf: Math.floor(Date.now()/1000) + 86400,
})
console.log('bypass nbf:', v2(futureToken))
// → { sub: 'bob', ... } ← not-yet-active token accepted as valid
Verified against fast-jwt@HEAD on 2026-06-03 (commit pulled today).
Cache side-effect
The verifier's LRU cache uses clockTolerance to compute the cache entry's expiry window:
src/verifier.js:121-134:
cacheValue[1] = ... payload.nbf * 1000 - clockTolerance : 0 // → -Infinity
cacheValue[2] = payload.exp * 1000 + clockTolerance // → Infinity
const maxTTL = clockTimestamp + clockTolerance + cacheTTL // → Infinity
With clockTolerance: Infinity, cache entries are stored with [min=-Infinity, max=Infinity]. The cache-hit check (min === 0 || now < min || now <= max) always passes for cached tokens.
Consequence: a developer who briefly sets clockTolerance: Infinity (e.g., during debug) and then removes it will find that any verifications performed during the debug window remain cached as valid until LRU eviction (default 1000 entries).
Asymmetric hardening — the smoking-gun shape
src/signer.js:98, 104 CORRECTLY uses Number.isFinite() to reject Infinity for expiresIn and notBefore:
expiresIn != null && Number.isFinite(expiresIn)
? Math.floor((iat + expiresIn) / 1000)
: ...
The verifier's clockTolerance validation doesn't apply the same guard. The same < 0 check pattern is also applied to clockTimestamp (line 527-529) and cacheTTL (line 535-537) — both also accept Infinity.
This is the kind of asymmetry that often indicates a missed hardening pass: the sign-side was hardened against Infinity but the verify-side wasn't.
Threat model
The bug requires the developer to (mis)configure clockTolerance: Infinity. Realistic ways this happens:
- Developer using Infinity as a sentinel for "disable expiry": common JS idiom; many libraries accept Infinity as "no limit." fast-jwt's signer treats Infinity as invalid (Number.isFinite false) but the verifier silently accepts it.
- JSON / env-var misconfig: config file or env var sets
clockToleranceto"Infinity"(string);Number("Infinity") === Infinity. Surprising via JSON.parse + Number cast or evenJSON.parse('{"clockTolerance": null}')if the codec accepts null → Infinity. - Test config bleed: integration tests use Infinity to make tokens never expire during long-running tests; the config bleeds into production.
For a JWT library, silently disabling token expiry on a "looks like a non-negative number" input is a security boundary failure.
Suggested fix
Single-line addition: use Number.isFinite() consistent with signer.js:
if (clockTolerance && (typeof clockTolerance !== 'number' || !Number.isFinite(clockTolerance) || clockTolerance < 0)) {
throw new TokenError(TokenError.codes.invalidOption, 'The clockTolerance option must be a finite, non-negative number.')
}
Same fix for clockTimestamp (line 527-529) and cacheTTL (line 535-537) for consistency.
Optional defense-in-depth: cap clockTolerance to a reasonable upper bound (e.g., 5 minutes = 300000 ms) with a process.emitWarning above that. Most legitimate use cases need <60s tolerance.
Affected versions
All versions since clockTolerance was first introduced in PR #193 (v1.5.1). Current main HEAD on 2026-06-03 is affected.
Reporter
Andrew Ridings (independent security researcher). Happy to coordinate disclosure timing and follow up with any clarifications. Email: ridingsa@gmail.com
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 6.2.4"
},
"package": {
"ecosystem": "npm",
"name": "fast-jwt"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "6.3.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-107721"
],
"database_specific": {
"cwe_ids": [
"CWE-613",
"CWE-682"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-08T22:02:02Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\n\n`createVerifier({ clockTolerance: Infinity })` silently bypasses both `exp` (expiry) AND `nbf` (not-before) validation. Any expired or not-yet-active token is accepted as valid. The same primitive also corrupts the verifier\u0027s internal cache so cached entries inherit infinite validity \u2014 they remain valid past a later developer-removed Infinity config until LRU eviction.\n\n## Vulnerable code\n\n`src/verifier.js:531-533` \u2014 option validation only rejects negative values, not Infinity:\n\n```js\nif (clockTolerance \u0026\u0026 (typeof clockTolerance !== \u0027number\u0027 || clockTolerance \u003c 0)) {\n throw new TokenError(TokenError.codes.invalidOption, \u0027The clockTolerance option must be a positive number.\u0027)\n}\n```\n\n`Infinity` passes (it\u0027s a number, not less than 0, truthy).\n\n`src/verifier.js:583-602` \u2014 clockTolerance flows into the date-claim validators:\n\n```js\nif (!ignoreNotBefore) {\n validators.push({ ..., modifier: -clockTolerance }) // \u2192 -Infinity\n}\nif (!ignoreExpiration) {\n validators.push({ ..., modifier: +clockTolerance }) // \u2192 Infinity\n}\n```\n\n`src/verifier.js:198-205` \u2014 applies modifier additively, producing always-pass comparisons:\n\n```js\nfunction validateClaimDateValue(value, modifier, now, greater, errorCode, errorVerb) {\n const adjusted = value * 1000 + (modifier || 0) // \u2192 \u00b1Infinity\n const valid = greater ? now \u003e= adjusted : now \u003c= adjusted // \u2192 always true\n ...\n}\n```\n\n## Empirical PoC\n\n```js\nconst { createSigner, createVerifier } = require(\u0027fast-jwt\u0027)\nconst secret = \u0027test-secret-with-enough-length-to-pass\u0027\n\nconst sign = createSigner({ key: secret, algorithm: \u0027HS256\u0027 })\nconst expiredToken = sign({\n sub: \u0027alice\u0027,\n iat: Math.floor(Date.now()/1000) - 3600,\n exp: Math.floor(Date.now()/1000) - 1800, // expired 30 min ago\n})\n\nconst v1 = createVerifier({ key: secret })\ntry { v1(expiredToken) } catch (e) { console.log(\u0027baseline rejects:\u0027, e.message) }\n// \u2192 \"The token has expired at ...\"\n\nconst v2 = createVerifier({ key: secret, clockTolerance: Infinity })\nconsole.log(\u0027bypass:\u0027, v2(expiredToken))\n// \u2192 { sub: \u0027alice\u0027, iat: ..., exp: ... } \u2190 expired token accepted as valid\n\n// Not-yet-active token (nbf in 1 day) \u2014 same bypass\nconst futureToken = sign({\n sub: \u0027bob\u0027,\n iat: Math.floor(Date.now()/1000),\n nbf: Math.floor(Date.now()/1000) + 86400,\n})\nconsole.log(\u0027bypass nbf:\u0027, v2(futureToken))\n// \u2192 { sub: \u0027bob\u0027, ... } \u2190 not-yet-active token accepted as valid\n```\n\nVerified against `fast-jwt@HEAD` on 2026-06-03 (commit pulled today).\n\n## Cache side-effect\n\nThe verifier\u0027s LRU cache uses `clockTolerance` to compute the cache entry\u0027s expiry window:\n\n`src/verifier.js:121-134`:\n```js\ncacheValue[1] = ... payload.nbf * 1000 - clockTolerance : 0 // \u2192 -Infinity\ncacheValue[2] = payload.exp * 1000 + clockTolerance // \u2192 Infinity\nconst maxTTL = clockTimestamp + clockTolerance + cacheTTL // \u2192 Infinity\n```\n\nWith `clockTolerance: Infinity`, cache entries are stored with `[min=-Infinity, max=Infinity]`. The cache-hit check (`min === 0 || now \u003c min || now \u003c= max`) always passes for cached tokens.\n\n**Consequence**: a developer who briefly sets `clockTolerance: Infinity` (e.g., during debug) and then removes it will find that any verifications performed during the debug window remain cached as valid until LRU eviction (default 1000 entries).\n\n## Asymmetric hardening \u2014 the smoking-gun shape\n\n`src/signer.js:98, 104` CORRECTLY uses `Number.isFinite()` to reject Infinity for `expiresIn` and `notBefore`:\n\n```js\nexpiresIn != null \u0026\u0026 Number.isFinite(expiresIn)\n ? Math.floor((iat + expiresIn) / 1000)\n : ...\n```\n\nThe verifier\u0027s `clockTolerance` validation doesn\u0027t apply the same guard. The same `\u003c 0` check pattern is also applied to `clockTimestamp` (line 527-529) and `cacheTTL` (line 535-537) \u2014 both also accept `Infinity`.\n\nThis is the kind of asymmetry that often indicates a missed hardening pass: the sign-side was hardened against Infinity but the verify-side wasn\u0027t.\n\n## Threat model\n\nThe bug requires the developer to (mis)configure `clockTolerance: Infinity`. Realistic ways this happens:\n\n1. **Developer using Infinity as a sentinel** for \"disable expiry\": common JS idiom; many libraries accept Infinity as \"no limit.\" fast-jwt\u0027s signer treats Infinity as invalid (Number.isFinite false) but the verifier silently accepts it.\n2. **JSON / env-var misconfig**: config file or env var sets `clockTolerance` to `\"Infinity\"` (string); `Number(\"Infinity\") === Infinity`. Surprising via JSON.parse + Number cast or even `JSON.parse(\u0027{\"clockTolerance\": null}\u0027)` if the codec accepts null \u2192 Infinity.\n3. **Test config bleed**: integration tests use Infinity to make tokens never expire during long-running tests; the config bleeds into production.\n\nFor a JWT library, silently disabling token expiry on a \"looks like a non-negative number\" input is a security boundary failure.\n\n## Suggested fix\n\nSingle-line addition: use `Number.isFinite()` consistent with signer.js:\n\n```js\nif (clockTolerance \u0026\u0026 (typeof clockTolerance !== \u0027number\u0027 || !Number.isFinite(clockTolerance) || clockTolerance \u003c 0)) {\n throw new TokenError(TokenError.codes.invalidOption, \u0027The clockTolerance option must be a finite, non-negative number.\u0027)\n}\n```\n\nSame fix for `clockTimestamp` (line 527-529) and `cacheTTL` (line 535-537) for consistency.\n\nOptional defense-in-depth: cap `clockTolerance` to a reasonable upper bound (e.g., 5 minutes = 300000 ms) with a `process.emitWarning` above that. Most legitimate use cases need \u003c60s tolerance.\n\n## Affected versions\n\nAll versions since clockTolerance was first introduced in PR #193 (v1.5.1). Current `main` HEAD on 2026-06-03 is affected.\n\n## Reporter\n\nAndrew Ridings (independent security researcher). Happy to coordinate disclosure timing and follow up with any clarifications. Email: ridingsa@gmail.com",
"id": "GHSA-687g-22h4-j4w4",
"modified": "2026-10-08T22:02:03Z",
"published": "2026-10-08T22:02:02Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/nearform/fast-jwt/security/advisories/GHSA-687g-22h4-j4w4"
},
{
"type": "WEB",
"url": "https://github.com/nearform/fast-jwt/commit/c0fb5b88b4c88ff2bdd194ca2c713599ad9e38b6"
},
{
"type": "PACKAGE",
"url": "https://github.com/nearform/fast-jwt"
},
{
"type": "WEB",
"url": "https://github.com/nearform/fast-jwt/releases/tag/v6.3.0"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "fast-jwt clockTolerance: Infinity silently bypasses both exp and nbf validation (and persists in the verifier cache)"
}
Mitigation
Set sessions/credentials expiration date.
No CAPEC attack patterns related to this CWE.