AOSSIE-Org / AOSSIE-Org/PictoPy

BUG:Wildcard CORS + credentials + no auth allows any webpage to read/delete the photo library

Offen
#1,360 4 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
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

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.