Langflow: IDOR/BOLA in Monitor API , Missing Ownership Enforcement on 7 Endpoints
High8.8CVE-2026-33760 · Published Jun 16, 2026 · updated Jul 20, 2026
### Summary Langflow's `/api/v1/monitor` router exposes 7 endpoints that perform read, write, and delete operations on user-owned resources , messages, sessions, build artifacts, and LLM transaction logs , without verifying that the authenticated requester owns the targeted resource. Any authenticated user can read, modify, rename, or permanently delete another user's data by supplying the target's resource ID or `flow_id`. This is a classic IDOR/BOLA vulnerability. Notably, the same source file (`monitor.py`) contains one correctly-implemented endpoint that uses an ownership check, demonstrating the correct pattern was known but inconsistently applied. ### Details **Source file: `src/backend/base/langflow/api/v1/monitor.py`** The correct pattern (used only in `GET /monitor/messages`, lines 77–80): ```python stmt = select(MessageTable) stmt = stmt.join(Flow, MessageTable.flow_id == Flow.id) stmt = stmt.where(Flow.user_id == current_user.id) # ownership enforced ``` All 7 vulnerable endpoints are missing this guard: **1. `GET /api/v1/monitor/builds` (lines 27–33)** , reads build data for any `flow_id`: ```python @router.get("/builds", dependencies=[Depends(get_current_acti...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| langflow PyPI | < 1.9.0 | 1.9.0 |
Details and references
### Summary Langflow's `/api/v1/monitor` router exposes 7 endpoints that perform read, write, and delete operations on user-owned resources , messages, sessions, build artifacts, and LLM transaction logs , without verifying that the authenticated requester owns the targeted resource. Any authenticated user can read, modify, rename, or permanently delete another user's data by supplying the target's resource ID or `flow_id`. This is a classic IDOR/BOLA vulnerability. Notably, the same source file (`monitor.py`) contains one correctly-implemented endpoint that uses an ownership check, demonstrating the correct pattern was known but inconsistently applied. ### Details **Source file: `src/backend/base/langflow/api/v1/monitor.py`** The correct pattern (used only in `GET /monitor/messages`, lines 77–80): ```python stmt = select(MessageTable) stmt = stmt.join(Flow, MessageTable.flow_id == Flow.id) stmt = stmt.where(Flow.user_id == current_user.id) # ownership enforced ``` All 7 vulnerable endpoints are missing this guard: **1. `GET /api/v1/monitor/builds` (lines 27–33)** , reads build data for any `flow_id`: ```python @router.get("/builds", dependencies=[Depends(get_current_active_user)]) async def get_vertex_builds(flow_id: Annotated[UUID, Query()], session: DbSession): vertex_builds = await get_vertex_builds_by_flow_id(session, flow_id) # no ownership check return VertexBuildMapModel.from_list_of_dicts(vertex_builds) ``` **2. `DELETE /api/v1/monitor/messages` (lines 102–107)** , deletes any message by UUID: ```python @router.delete("/messages", status_code=204, dependencies=[Depends(get_current_active_user)]) async def delete_messages(message_ids: list[UUID], session: DbSession): await session.exec(delete(MessageTable).where(MessageTable.id.in_(message_ids))) # message_ids accepted verbatim, no ownership check ``` **3. `PUT /api/v1/monitor/messages/{message_id}` (lines 110–134)** , overwrites any message: ```python db_message = await session.get(MessageTable, message_id) # no check: db_message.flow_id → Flow.user_id == current_user.id db_message.sqlmodel_update(message_dict) ``` **4. `PATCH /api/v1/monitor/messages/session/{old_session_id}` (lines 137–171)** , renames any session: ```python stmt = select(MessageTable).where(MessageTable.session_id == old_session_id) # no JOIN to Flow, no WHERE Flow.user_id == current_user.id ``` **5. `DELETE /api/v1/monitor/messages/session/{session_id}` (lines 174–188)** , bulk-deletes any session: ```python await session.exec( delete(MessageTable).where(col(MessageTable.session_id) == session_id) # no ownership filter ) ``` **6. `GET /api/v1/monitor/transactions` (lines 191–211)** , reads LLM prompt/response logs for any `flow_id`: ```python stmt = select(TransactionTable).where(TransactionTable.flow_id == flow_id) # no JOIN to Flow, no WHERE Flow.user_id == current_user.id ``` **7. `DELETE /api/v1/monitor/builds`** , deletes build records for any `flow_id`: Shares the same root cause as endpoint #1 (`GET /builds`): `flow_id` is accepted as a bare query parameter and passed to the deletion path without a `WHERE Flow.user_id == current_user.id` ownership check, so any authenticated user can destroy another user's build artifacts. ### PoC Tested on Langflow v1.7.3 (`langflowai/langflow:1.7.3`) with two accounts: `langflow` (victim) and `attacker_test` (attacker). ```bash # Setup: authenticate both users TOKEN=$(curl -s -X POST http://localhost:7860/api/v1/login \ -d "username=langflow&password=langflow" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])") ATTKR=$(curl -s -X POST http://localhost:7860/api/v1/login \ -d "username=attacker_test&password=Attacker123" \ | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])") # Victim creates a flow (attacker only needs to know the flow_id , obtainable via brute force or enumeration) FLOW_ID=$(curl -s -X POST http://localhost:7860/api/v1/flows/ \
- CVSS 3.1
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
- Severity from
- GitHub (reviewed advisory)
- Weakness
- CWE-639
- Also known as
- CVE-2026-33760, PYSEC-2026-242
More Langflow advisories
All Langflow| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Jun 19 | Langflow: Logout button does not clear session | Medium6.1 | 1.7.0 |
| Jun 19 | Langflow: insecure direct object reference | High8.4 | 1.9.1 |
| Jun 17 | Langflow: Unauthenticated file upload leads to DoS (space exhaustion) and information leak | Critical9.3 | 1.9.1 |
| Jun 16 | Langflow: Unauthenticated Shareable Playground arbitrary local or S3 file read | Medium6.1 | 1.10.0 |
| Jun 16 | Langflow: Unauthenticated RCE in Shareable Playgrounds | Critical9.6 | 1.9.2 |
| Jun 16 | Langflow: Path Traversal in Knowledge Bases API via Creation Endpoint | Medium6.5 | 1.9.0 |