AOSSIE-Org / AOSSIE-Org/PictoPy
BUG:Wildcard CORS + credentials + no auth allows any webpage to read/delete the photo library
- Vorherrschende Sprache
- Python
- Sterne
- 283
- Forks
- 679
- Ø Merge
- 7 T. 2 Std.
- Gemergte PRs (30 T.)
- 3
Beschreibung
### Is there an existing issue for this?
- [x] I have searched the existing issues
### What happened?
### Summary
Both local FastAPI servers (`backend` on `:52123` and `sync-microservice` on `:52124`) are configured with:
```python
allow_origins=["*"]
allow_credentials=True
allow_methods=["*"]
allow_headers=["*"]
```
This combination means the browser will expose credentialed cross-origin responses to *any* origin. Since there's no authentication on top of it, any webpage the user has open in a normal browser tab — while PictoPy is running in the background — can talk directly to these servers.
### Affected files
- `backend/main.py:124-130`
- `sync-microservice/main.py:36-42`
### Impact
With the app simply running, a malicious or compromised webpage can, without any user interaction:
- Enumerate the entire photo library via `GET /images/`, including file paths, GPS/EXIF data, and timestamps
- Delete folders and cascade-delete images/faces/albums via `DELETE /folders/delete-folders`
- Delete ML models via `DELETE /models/facenet`
- Shut down the backend via `POST /shutdown`
- Leak absolute local folder paths (OS username, directory layout) via the sync-microservice's status endpoints
- Disrupt sync or kill the sync-microservice via unauthenticated POSTs (`/watcher/stop`, `/shutdown`)
This also compounds other findings — e.g. the unrestricted `folder_path` in `POST /folders/add-folder` becomes remotely triggerable once this is fixed to require auth, it's no longer exploitable from an arbitrary webpage.
### Steps to reproduce
1. Run PictoPy normally.
2. In a separate, unrelated browser tab, open a page containing:
```js
fetch('http://localhost:52123/images/').then(r => r.json()).then(console.log)
```
3. Observe the full image index (including GPS data) returned to a page with no relation to PictoPy.
### Proposed fix
1. **Restrict CORS to the actual app origin(s)** instead of `*`:
```python
allow_origins=["tauri://localhost", "http://localhost:1420"]
```
2. **Drop `allow_credentials=True`** unless cookies/sessions are actually required — this alone prevents cross-origin scripts from reading responses even if an origin match occurs.
3. **Add a local shared-secret token**, generated at process startup, written to a file only the Tauri process can read, and required on every request via a header (e.g. `X-PictoPy-Token`). This protects against DNS-rebinding-style attacks that could still spoof an allowed origin.
4. Apply the same fix to `sync-microservice/main.py`.
### Acceptance criteria
- [ ] `allow_origins` set to an explicit list, not `*`
- [ ] `allow_credentials` set to `False` unless a concrete need is documented
- [ ] All state-changing and data-reading endpoints require a valid local auth token
- [ ] Token is generated per-process-start and stored with restrictive file permissions (`0600`)
- [ ] Fix applied to both `backend` and `sync-microservice`
- [ ] Manual test: a `fetch()` from an arbitrary origin (not the app's own) is rejected with `401`
### Record
- [x] I agree to follow this project's Code of Conduct
Beitragsleitfaden
Bewertung
Dieses Issue wurde noch nicht bewertet.