Behebt die Befunde aus dem Security-Audit (Lauf 1, Commit c1afa02). Zu jedem Fix gibt es Tests; die 6 Fingerprint-/Kennzahlen-Tests, die auch auf main fehlschlagen (pdf.js unter Jest), sind unverändert.
Was sich ändert
Hoch
Rechteausweitung über API-Keys: /api/api-keys nur noch mit MANAGE_SETTINGS. API-Keys umgehen keine Rechteprüfung mehr, sie gelten nur auf Routen mit @AllowApiKey() (Paperless-Webhook, externer Upload, checksum, Agent-Routen des Etikettendrucks).
Serverdateien per Mail auslesen: send-email prüft den Body streng, nodemailer läuft mit disableFileAccess/disableUrlAccess.
DoS durch PDF-Dekompressionsbomben: Vorab-Check (256 MB entpackt) vor pdf.js (Fingerprint) und pdf-lib (E-Rechnung). Ghostscript läuft mit -dSAFER statt -dNOSAFER, mit Timeout und max. 500 Seiten.
Mittel/Niedrig
PermissionsGuarddeny by default: jede Route braucht @RequirePermissions, @AllowAnyAuthenticated oder @Public. routen-rechte.spec.ts prüft alle Routen.
Posteingangs-Maske ändert nur Dokumente im eigenen Bereich (Tag 1 bzw. Manuell-Tag); Freigabe (CF15) und Zahlung (CF16) nur mit der jeweiligen Rolle.
Etiketten-Agent: printed/error nur für abgeholte, offene Jobs (sonst 409); Feldwerte nur aus der Vorlage und URL-kodiert.
Path-Traversal in den Mail-Vorschau-Routen, Symlinks auf der Scan-Freigabe, Exportdateinamen, Belegnummer-URL.
JWT: Audience wird gegen OIDC_CLIENT_ID geprüft.
Fachliche Änderungen
PM_Buchhaltung umfasst jetzt PM_Posteingang (Menüpunkt und Tagesbericht-Kachel „Posteingang“ für die Buchhaltung).
Behebt die Befunde aus dem Security-Audit (Lauf 1, Commit `c1afa02`). Zu jedem Fix gibt es Tests; die 6 Fingerprint-/Kennzahlen-Tests, die auch auf `main` fehlschlagen (pdf.js unter Jest), sind unverändert.
## Was sich ändert
**Hoch**
- **Rechteausweitung über API-Keys**: `/api/api-keys` nur noch mit `MANAGE_SETTINGS`. API-Keys umgehen keine Rechteprüfung mehr, sie gelten nur auf Routen mit `@AllowApiKey()` (Paperless-Webhook, externer Upload, `checksum`, Agent-Routen des Etikettendrucks).
- **Serverdateien per Mail auslesen**: `send-email` prüft den Body streng, nodemailer läuft mit `disableFileAccess`/`disableUrlAccess`.
- **DoS durch PDF-Dekompressionsbomben**: Vorab-Check (256 MB entpackt) vor pdf.js (Fingerprint) und pdf-lib (E-Rechnung). Ghostscript läuft mit `-dSAFER` statt `-dNOSAFER`, mit Timeout und max. 500 Seiten.
**Mittel/Niedrig**
- `PermissionsGuard` **deny by default**: jede Route braucht `@RequirePermissions`, `@AllowAnyAuthenticated` oder `@Public`. `routen-rechte.spec.ts` prüft alle Routen.
- Posteingangs-Maske ändert nur Dokumente im eigenen Bereich (Tag 1 bzw. Manuell-Tag); Freigabe (CF15) und Zahlung (CF16) nur mit der jeweiligen Rolle.
- Etiketten-Agent: `printed`/`error` nur für abgeholte, offene Jobs (sonst 409); Feldwerte nur aus der Vorlage und URL-kodiert.
- Path-Traversal in den Mail-Vorschau-Routen, Symlinks auf der Scan-Freigabe, Exportdateinamen, Belegnummer-URL.
- JWT: Audience wird gegen `OIDC_CLIENT_ID` geprüft.
**Fachliche Änderungen**
- `PM_Buchhaltung` umfasst jetzt `PM_Posteingang` (Menüpunkt und Tagesbericht-Kachel „Posteingang“ für die Buchhaltung).
- Routen umbenannt: `paperless/inbox/:id[/pdf|/preview|/erechnung]` → `paperless/documents/:id[/pdf|/preview|/erechnung]` (ohne Alias).
- Dokumentsuche und `documents/:id` liefern nur noch id, Titel, ASN, Datum (kein OCR-Volltext).
## Nach dem Deployment prüfen
- [ ] **Login** funktioniert (Audience-Check). Sonst steht im Backend-Log `jwt audience invalid` → `OIDC_CLIENT_ID` prüfen. `docker-compose.yml` übergibt jetzt standardmäßig dieselbe Client-ID wie das Frontend.
- [ ] **Etiketten-Agent** holt Jobs ab und meldet `printed`.
- [ ] **Paperless-Webhook** und **externer Upload** laufen (API-Key).
- [ ] Andere Skripte/n8n mit API-Key? Die bekommen jetzt 403 – im Log steht Route und Key-Name.
- [ ] **Scanner**: Neue Scans landen im Posteingang (Ghostscript mit `-dSAFER`); Symlinks auf der Freigabe werden übersprungen.
- [ ] **Posteingang/Manuell**: Vorschau, PDF, Speichern, Verknüpfungssuche; Duplikatvergleich in Scanner und Mail-Import.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
- ApiKeysController verlangt MANAGE_SETTINGS. Bisher konnte jeder
OIDC-Benutzer einen API-Key erzeugen, der im PermissionsGuard jede
Rechteprüfung umgeht (Rechteausweitung zum Admin).
- MailService setzt disableFileAccess/disableUrlAccess für jede Mail.
- send-email im Posteingang prüft den Body streng auf Strings/Zahlen.
Bisher liest nodemailer bei html: { path: '/proc/self/environ' }
beliebige Serverdateien ein und verschickt sie.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Ghostscript läuft auf PDFs aus Mails und vom Scanner jetzt mit -dSAFER
statt -dNOSAFER (kein Datei-/Prozesszugriff aus PostScript), mit
Timeout (60 s je Seite, 10 min je Dokument, SIGKILL) und höchstens
500 gerenderten Seiten. Temp-Dateien werden auch im Fehlerfall
entfernt. Ungenutztes getPageCount (brauchte Dateizugriff) entfernt.
- Neuer Vorab-Check ueberschreitetDekompressionsLimit (256 MB, streamend,
erkennt auch Deflate-Ketten und abgeschnittene Streams). Fingerprint
(pdf.js) und E-Rechnungs-Extraktion (pdf-lib) laden Bomben nicht mehr;
eine einzelne Mail konnte das Backend sonst per OOM dauerhaft lahmlegen.
- Verschlüsselte PDFs bekommen keinen Inhalts-Fingerprint mehr ('' =
nicht vergleichbar), weil pdf.js sie erst intern entschlüsselt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- PermissionsGuard lehnt Routen ohne @RequirePermissions/@AllowAnyAuthenticated
ab. API-Keys umgehen keine Rechteprüfung mehr, sondern gelten nur auf
Routen mit @AllowApiKey (Paperless-Webhook, externer Upload, checksum,
Agent-Routen des Etikettendrucks).
- Rechte für 24 bisher offene Routen ergänzt, u.a. paperless/documents
(nur Admin), paperless/documents/:id und Kontonummern (Posteingang/
manuell), webhook/status (Admin). routen-rechte.spec.ts prüft alle Routen.
- Etiketten-Agent: printed/error nur für abgeholte, offene Jobs (bedingtes
Update, sonst 409) – ein gedruckter Job kann seine Nummer nicht mehr
freigeben. Feldwerte nur aus den Eingabefeldern der Vorlage ({number}
nicht vorgebbar) und URL-kodiert in GET-/Callback-URLs.
- PUT paperless/inbox/:id ignoriert Freigabe (CF15) und Zahlung (CF16)
ohne die jeweilige Rolle (Funktionstrennung).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PUT paperless/inbox/:id prüft jetzt pro Dokument: Posteingang-Rolle nur
für Dokumente mit Tag 1 (Posteingang), Buchhaltung nur für Dokumente mit
MANUELL_BEARBEITEN_TAG, Admins immer. Bisher ließen sich Mandant (Owner),
Felder und Titel beliebiger Paperless-Dokumente ändern, weil das Backend
mit dem Service-Token arbeitet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der Posteingang ist eine abgespeckte Buchhaltung. Bisher bekam
PM_Buchhaltung nur PROCESS_MANUALLY; die Seite „Manuell bearbeiten“
nutzt für Vorschau, PDF, E-Rechnung und Speichern aber Routen mit
VIEW_INBOX – reine Buchhaltungsnutzer konnten dort nichts speichern.
PM_Buchhaltung bekommt jetzt zusätzlich VIEW_INBOX (Backend und Frontend).
permissions.enum.spec.ts vergleicht künftig nicht nur die Gruppennamen,
sondern auch die Berechtigungen pro Gruppe zwischen beiden Kopien.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
„inbox“ war doppelt belegt (/api/inbox = Scanner, /api/paperless/inbox =
Paperless-Posteingang) und passte nicht zur Manuell-Seite, die dieselben
Routen nutzt. Umbenannt (ohne Alias, nur das eigene Frontend nutzt sie):
PUT paperless/inbox/:id → PUT paperless/documents/:id
GET paperless/inbox/pdf/:id → GET paperless/documents/:id/pdf
GET paperless/inbox/preview/:id → GET paperless/documents/:id/preview
GET paperless/inbox/:id/erechnung → GET paperless/documents/:id/erechnung
Dabei:
- Dokumentsuche (GET documents) wieder für den Posteingang (VIEW_INBOX)
statt nur Admin – die Verknüpfungssuche im Bearbeiten-Dialog nutzt sie;
die Einschränkung aus dem vorigen Commit hatte sie gebrochen.
- Suche und GET documents/:id liefern nur noch id, Titel, ASN, Datum
(kein OCR-Volltext, keine Statusfelder).
- documents/:id/pdf auch für VIEW_SCANNER (Duplikatvergleich im Scanner).
- E-Rechnungs-Vorschlag prüft wie das Speichern pro Dokument (Tag 1 bzw.
Manuell-Tag); Vorschau/PDF bewusst nicht (Suchergebnisse, Duplikate).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
attachments/:attachmentId/pages/:page/{thumb,preview} übernahm die ID
ungeprüft in den Dateipfad – mit `..%2Finbox%2F<uuid>` ließen sich
Scanner-Vorschauen anderer Benutzer aus /mnt/data/inbox lesen.
- Routen wandeln attachmentId und page per ParseIntPipe in Zahlen um.
- EmailPageCacheService nimmt nur positive ganze Zahlen als Anhang-ID und
Seite an, PageCacheService (Scanner) nur UUIDs als Dokument-ID.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bisher prüfte das Backend nur Issuer und Signatur. Ein Access-Token, das
derselbe Authentik-Provider für eine andere Anwendung ausgestellt hat,
wurde ebenfalls akzeptiert.
- JwtStrategy verlangt aud == OIDC_CLIENT_ID (jwt-optionen.ts, getestet
mit echten RS256-Tokens). Ohne OIDC_CLIENT_ID bleibt die Prüfung aus,
mit Warnung beim Start.
- docker-compose.yml übergibt OIDC_CLIENT_ID jetzt ans Backend, Standard:
dieselbe Client-ID wie das Frontend (VITE_OIDC_CLIENT_ID).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Scanner: Dateien von der Scan-Freigabe werden nur übernommen, wenn sie
reguläre Dateien in echten Verzeichnissen sind. chokidar folgt keinen
Symlinks mehr; beim Kopieren über Mount-Grenzen (/mnt/scans → /mnt/data)
wird mit O_NOFOLLOW geöffnet und nur exklusiv geschrieben. Bisher holte
ein Symlink wie scan.pdf -> /proc/self/environ die Zieldatei in den
Posteingang.
- Export: Dateinamen (enthalten u.a. Barcode-Werte) werden auf ein
Pfadsegment reduziert – „../“ verlässt den FTP-Zielordner nicht mehr.
- Belegnummer: {Jahr}/{Nummer} werden URL-kodiert in BELEGNUMMER_*_URL
eingesetzt (Nummer stammt aus Request bzw. gedrucktem Barcode);
belegnummer/release prüft die Typen im Body.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DuplikatVergleichModal lädt das vorhandene Paperless-Dokument über
documents/:id/pdf – auch im Mail-Import (VIEW_MAIL). Die Route verlangte
nur VIEW_INBOX/VIEW_SCANNER, reine Mail-Nutzer bekamen 403.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Behebt die Befunde aus dem Security-Audit (Lauf 1, Commit
c1afa02). Zu jedem Fix gibt es Tests; die 6 Fingerprint-/Kennzahlen-Tests, die auch aufmainfehlschlagen (pdf.js unter Jest), sind unverändert.Was sich ändert
Hoch
/api/api-keysnur noch mitMANAGE_SETTINGS. API-Keys umgehen keine Rechteprüfung mehr, sie gelten nur auf Routen mit@AllowApiKey()(Paperless-Webhook, externer Upload,checksum, Agent-Routen des Etikettendrucks).send-emailprüft den Body streng, nodemailer läuft mitdisableFileAccess/disableUrlAccess.-dSAFERstatt-dNOSAFER, mit Timeout und max. 500 Seiten.Mittel/Niedrig
PermissionsGuarddeny by default: jede Route braucht@RequirePermissions,@AllowAnyAuthenticatedoder@Public.routen-rechte.spec.tsprüft alle Routen.printed/errornur für abgeholte, offene Jobs (sonst 409); Feldwerte nur aus der Vorlage und URL-kodiert.OIDC_CLIENT_IDgeprüft.Fachliche Änderungen
PM_Buchhaltungumfasst jetztPM_Posteingang(Menüpunkt und Tagesbericht-Kachel „Posteingang“ für die Buchhaltung).paperless/inbox/:id[/pdf|/preview|/erechnung]→paperless/documents/:id[/pdf|/preview|/erechnung](ohne Alias).documents/:idliefern nur noch id, Titel, ASN, Datum (kein OCR-Volltext).Nach dem Deployment prüfen
jwt audience invalid→OIDC_CLIENT_IDprüfen.docker-compose.ymlübergibt jetzt standardmäßig dieselbe Client-ID wie das Frontend.printed.-dSAFER); Symlinks auf der Freigabe werden übersprungen.🤖 Generated with Claude Code
- ApiKeysController verlangt MANAGE_SETTINGS. Bisher konnte jeder OIDC-Benutzer einen API-Key erzeugen, der im PermissionsGuard jede Rechteprüfung umgeht (Rechteausweitung zum Admin). - MailService setzt disableFileAccess/disableUrlAccess für jede Mail. - send-email im Posteingang prüft den Body streng auf Strings/Zahlen. Bisher liest nodemailer bei html: { path: '/proc/self/environ' } beliebige Serverdateien ein und verschickt sie. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>- Ghostscript läuft auf PDFs aus Mails und vom Scanner jetzt mit -dSAFER statt -dNOSAFER (kein Datei-/Prozesszugriff aus PostScript), mit Timeout (60 s je Seite, 10 min je Dokument, SIGKILL) und höchstens 500 gerenderten Seiten. Temp-Dateien werden auch im Fehlerfall entfernt. Ungenutztes getPageCount (brauchte Dateizugriff) entfernt. - Neuer Vorab-Check ueberschreitetDekompressionsLimit (256 MB, streamend, erkennt auch Deflate-Ketten und abgeschnittene Streams). Fingerprint (pdf.js) und E-Rechnungs-Extraktion (pdf-lib) laden Bomben nicht mehr; eine einzelne Mail konnte das Backend sonst per OOM dauerhaft lahmlegen. - Verschlüsselte PDFs bekommen keinen Inhalts-Fingerprint mehr ('' = nicht vergleichbar), weil pdf.js sie erst intern entschlüsselt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>- PermissionsGuard lehnt Routen ohne @RequirePermissions/@AllowAnyAuthenticated ab. API-Keys umgehen keine Rechteprüfung mehr, sondern gelten nur auf Routen mit @AllowApiKey (Paperless-Webhook, externer Upload, checksum, Agent-Routen des Etikettendrucks). - Rechte für 24 bisher offene Routen ergänzt, u.a. paperless/documents (nur Admin), paperless/documents/:id und Kontonummern (Posteingang/ manuell), webhook/status (Admin). routen-rechte.spec.ts prüft alle Routen. - Etiketten-Agent: printed/error nur für abgeholte, offene Jobs (bedingtes Update, sonst 409) – ein gedruckter Job kann seine Nummer nicht mehr freigeben. Feldwerte nur aus den Eingabefeldern der Vorlage ({number} nicht vorgebbar) und URL-kodiert in GET-/Callback-URLs. - PUT paperless/inbox/:id ignoriert Freigabe (CF15) und Zahlung (CF16) ohne die jeweilige Rolle (Funktionstrennung). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>attachments/:attachmentId/pages/:page/{thumb,preview} übernahm die ID ungeprüft in den Dateipfad – mit `..%2Finbox%2F<uuid>` ließen sich Scanner-Vorschauen anderer Benutzer aus /mnt/data/inbox lesen. - Routen wandeln attachmentId und page per ParseIntPipe in Zahlen um. - EmailPageCacheService nimmt nur positive ganze Zahlen als Anhang-ID und Seite an, PageCacheService (Scanner) nur UUIDs als Dokument-ID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>- Scanner: Dateien von der Scan-Freigabe werden nur übernommen, wenn sie reguläre Dateien in echten Verzeichnissen sind. chokidar folgt keinen Symlinks mehr; beim Kopieren über Mount-Grenzen (/mnt/scans → /mnt/data) wird mit O_NOFOLLOW geöffnet und nur exklusiv geschrieben. Bisher holte ein Symlink wie scan.pdf -> /proc/self/environ die Zieldatei in den Posteingang. - Export: Dateinamen (enthalten u.a. Barcode-Werte) werden auf ein Pfadsegment reduziert – „../“ verlässt den FTP-Zielordner nicht mehr. - Belegnummer: {Jahr}/{Nummer} werden URL-kodiert in BELEGNUMMER_*_URL eingesetzt (Nummer stammt aus Request bzw. gedrucktem Barcode); belegnummer/release prüft die Typen im Body. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>