Soumettre #838497: AIDC-AI ComfyUI-Copilot 2.0.28 Insecure Direct Object Reference (IDOR) / Cross-Tenant Data Expoinformation

TitreAIDC-AI ComfyUI-Copilot 2.0.28 Insecure Direct Object Reference (IDOR) / Cross-Tenant Data Expo
Description## Vulnerability Title Cross-Tenant Data Exposure via Hash-Key Confusion in Workflow Checkpoint Restore ## Affected Component `backend/controller/conversation_api.py` and `backend/dao/workflow_table.py` Repository: https://github.com/AIDC-AI/ComfyUI-Copilot ## Summary An attacker with access to the checkpoint restore endpoint can request a different user's `version_id`, causing application-level object-key reuse, which leads to unauthorized retrieval of saved workflow checkpoint data. The application treats the client-supplied `version_id` as sufficient proof of access to a workflow checkpoint, negatively impacting users whose workflow data is stored in `workflow_version`. ## Technical Details The vulnerability occurs because the workflow checkpoint restore path uses a bare integer `version_id` as the security-relevant object key. The saved record contains `session_id`, `workflow_data`, `workflow_data_ui`, and `attributes`, but the restore path does not bind the requested checkpoint to the caller's session, user, tenant, or permission context before returning the saved workflow payload. **Where the Identity Key is Extracted** In `backend/controller/conversation_api.py`, the restore endpoint accepts `version_id` from the query string and uses it as the only selector for the persisted workflow checkpoint. No request header, authenticated principal, or `session_id` comparison is performed before returning `workflow_data` and `workflow_data_ui`: ```python @server.PromptServer.instance.routes.get("/api/restore-workflow-checkpoint") async def restore_workflow_checkpoint(request): try: version_id = request.query.get('version_id') # ... validation ... version_id = int(version_id) # Get workflow data by version ID workflow_version = get_workflow_data_by_id(version_id) # ... return web.json_response({ "success": True, "data": { "version_id": version_id, "workflow_data": workflow_version.get('workflow_data'), "workflow_data_ui": workflow_version.get('workflow_data_ui'), "attributes": workflow_version.get('attributes'), "created_at": workflow_version.get('created_at') }, "message": f"Workflow checkpoint restored successfully" }) ``` The Data Access Object (DAO) confirms that the database query is keyed only by the primary key `id` (`backend/dao/workflow_table.py`): ```python def get_workflow_version_by_id(self, version_id: int) -> Optional[Dict[str, Any]]: session = self.get_session() try: version = session.query(WorkflowVersion)\ .filter(WorkflowVersion.id == version_id)\ .first() # ... ``` Equality of `version_id` only means two requests name the same database row. Because the restore path has no ownership or permission revalidation, object-key equality is incorrectly treated as authorization equivalence. ## Impact This vulnerability allows attackers to: - Read another user's saved `workflow_data` and `workflow_data_ui`. - Enumerate sequential checkpoint IDs to discover private workflow artifacts. - Reuse persisted checkpoint records across security boundaries until the database is invalidated or migrated. The attack is persistent: workflow checkpoint rows generated with the vulnerable object-key scheme remain readable by `version_id` until the checkpoint store is cleared, migrated, or protected by read-time authorization checks. ## Proof of Concept The test simulates Alice saving a private checkpoint and Bob restoring Alice's checkpoint by changing only the `version_id`. ```python #!/usr/bin/env python3 """Minimal PoC for checkpoint object-key confusion.""" alice_save = await save_workflow_checkpoint(FakeRequest({ "session_id": "alice_session", "workflow_api": { "owner_marker": "ALICE_PRIVATE_WORKFLOW", "prompt": "private prompt only Alice should see" }, "workflow_ui": {"ui_owner_marker": "ALICE_PRIVATE_UI"}, "checkpoint_type": "debug_start", }, headers={"Authorization": "Bearer alice-token"})) alice_version = alice_save.data["data"]["version_id"] # Bob supplies his own request metadata but targets Alice's version_id. bob_restore_alice = await restore_workflow_checkpoint(FakeRequest( query={"version_id": str(alice_version)}, headers={"Authorization": "Bearer bob-token", "X-Session-ID": "bob_session"}, )) restored = bob_restore_alice.data["data"] assert bob_restore_alice.data["success"] is True assert restored["workflow_data"]["owner_marker"] == "ALICE_PRIVATE_WORKFLOW" assert restored["workflow_data_ui"]["ui_owner_marker"] == "ALICE_PRIVATE_UI" print("vulnerability_reproduced True") ``` ## Remediation Bind checkpoint records to a server-side authenticated principal and revalidate authorization before returning checkpoint data. Do not rely on a client-supplied integer `version_id` as the sole object identity for restore operations. Example implementation change: ```python # In backend/controller/conversation_api.py workflow_version = get_workflow_data_by_id_for_owner( version_id=version_id, owner_id=current_user.id, session_id=current_session_id, ) if not workflow_version: return web.json_response({ "success": False, "message": "Workflow version not found" }, status=404) ``` Additional mitigations: 1. Complete Field Coverage: Include all fields relevant to authorization, ownership, tenant isolation, and checkpoint schema validity. 2. Domain Separation: Separate checkpoint namespaces across users, tenants, sessions, and object types. 3. Read-Time Revalidation: Re-check ownership and policy before returning any persisted workflow checkpoint. ## References - Save/Restore handler logic: `https://github.com/AIDC-AI/ComfyUI-Copilot/blob/c2502d728d59ca2aed4d9002ea37bcb84ed11bff/backend/controller/conversation_api.py` - Database table query bindings: `https://github.com/AIDC-AI/ComfyUI-Copilot/blob/c2502d728d59ca2aed4d9002ea37bcb84ed11bff/backend/dao/workflow_table.py` - Frontend API call endpoint structure: `https://github.com/AIDC-AI/ComfyUI-Copilot/blob/c2502d728d59ca2aed4d9002ea37bcb84ed11bff/ui/src/apis/workflowChatApi.ts`
La source⚠️ https://github.com/AIDC-AI/ComfyUI-Copilot/issues/149
Utilisateur
 dem0000 (UID 98390)
Soumission27/05/2026 10:04 (il y a 1 mois)
Modérer27/06/2026 19:03 (1 month later)
StatutAccepté
Entrée VulDB374489 [AIDC-AI ComfyUI-Copilot jusqu’à 2.0.28 Workflow Checkpoint Restore conversation_api.py élévation de privilèges]
Points20

Interested in the pricing of exploits?

See the underground prices here!