Τι συνέβη
Στις 8 Σεπτεμβρίου 2026, ο ερευνητής Gadi Evron της Knostic ενημέρωσε την Cloudflare μέσω HackerOne ότι πολύ μεγάλα prompts προς το GLM-5.3 επέστρεφαν κείμενο που ανήκε σε άλλες συνεδρίες χρηστών. Η Cloudflare αναπαρήγαγε το πρόβλημα το επόμενο πρωί, έθεσε το μοντέλο offline μέσα σε 40 λεπτά από την κήρυξη περιστατικού και το επανέφερε την ίδια μέρα με διορθωμένη ρύθμιση και patched engine.
Ανάμεσα στις 27 Αυγούστου (ημέρα launch) και τις 9 Σεπτεμβρίου, μικρός αριθμός πελατών έλαβε απαντήσεις που περιείχαν δεδομένα από προηγούμενα requests άλλων πελατών στο ίδιο μοντέλο. Συνολικά επηρεάστηκαν 155 απαντήσεις, όλες σε prompts μεγαλύτερα από 681.280 tokens.
Η δημοσίευση έγινε στις 26 Οκτωβρίου 2026, σε συντονισμό με την ομάδα του SGLang (RadixArk) και τον ερευνητή. Το ίδιο bug class αφορά isolation σε multi-tenant LLM serving: το KV cache είναι κοινό pool σελίδων στη GPU μνήμη και η ιδιοκτησία των σελίδων πρέπει να είναι αλάνθαστη.
Πώς σερβίρεται το GLM-5.3
Το Workers AI τρέχει το GLM-5.3 με SGLang σε disaggregated διάταξη:
- Prefill GPUs: επεξεργάζονται το prompt και παράγουν το KV cache.
- RDMA / Mooncake: μεταφέρουν το cache στο decode cluster.
- Decode GPUs: γεννούν την απάντηση token-token, διαβάζοντας αυτό το cache.
Το KV cache είναι κοινό pool σταθερού μεγέθους σελίδων. Κάθε request παίρνει σελίδες στην εισδοχή και τις απελευθερώνει όταν τελειώσει. Οι σελίδες δεν μηδενίζονται ανάμεσα σε requests: το επόμενο request απλώς τις ξαναγράφει. Αυτό είναι συνηθισμένο για απόδοση. Σημαίνει όμως ότι ο engine είναι υπεύθυνος να μην αφήσει decode να διαβάσει σελίδες που δεν έγραψε το τρέχον request.
Το μέγεθος του pool δεν είναι ξεχωριστό config value. Το SGLang το υπολογίζει στο startup από την ελεύθερη GPU μνήμη μετά τη φόρτωση των βαρών. Το advertised context length είναι άλλο config. Τίποτα δεν τα υποχρεώνει να συμφωνούν.
Δύο overlapping προβλήματα
1. Misconfiguration
Στα prefill nodes του GLM-5.3, το KV pool χωρούσε 681.280 tokens, ενώ το μοντέλο διαφημιζόταν με context 1.048.576 tokens. Η ομάδα το ήξερε πριν το launch. Περίμενε ότι ο engine θα γυρίσει σφάλμα για prompt που δεν χωράει. Τα long-context tests επέστρεφαν HTTP 200 και streaming body χωρίς error frames, οπότε θεώρησαν ότι «κάπως το χειρίζεται».
Το κενό στο testing: ελέγχθηκαν status codes και απόδοση, όχι συνοχή και περιεχόμενο εξόδου.
2. Bug στο SGLang (disaggregated mode)
Όταν ένα prompt ξεπερνούσε το pool, ο scheduler το απέρριπτε εσωτερικά και το αντικαθιστούσε με placeholder ενός token, ώστε να στραγγίξει από το batch χωρίς πραγματική δέσμευση μνήμης. Σε single-node αυτό δούλευε: ο client έπαιρνε error.
Σε disaggregated prefill/decode, οι ουρές εισδοχής έλεγχαν αν το request είναι finished, όχι αν είναι rejected. Το rejected request φαινόταν ζωντανό.
Αποτέλεσμα: HTTP 200 αντί για 400. Το prompt_tokens ταίριαζε με το μεγάλο prompt. Η απάντηση ήταν συνεκτική, ερχόταν πιο γρήγορα από ό,τι έπρεπε για 8 σελίδες prefill, και μπορούσε να περιέχει prompts ή μερικές γεννήσεις άλλων χρηστών.
Κάθε request πάνω από το όριο συμπεριφερόταν έτσι. Παρόμοιο ζήτημα είχε αναφερθεί στο SGLang ως issue #30233 στις 6 Ιουλίου 2026. Το patch μπήκε στο v0.5.20, με follow-ups στα v0.5.21 και v0.5.22.
Χρονολόγιο (UTC)
| Πότε | Τι |
|---|---|
| 27 Αυγ 2026 | Launch GLM-5.3 με pool μικρότερο από το context. Η έκθεση υπάρχει από την πρώτη μέρα. |
| 8 Σεπτ 23:11 | Report μέσω HackerOne. |
| 9 Σεπτ 08:00 | Έναρξη επαλήθευσης. |
| 9 Σεπτ 13:22 | Κήρυξη security incident. Αναπαραγωγή με δύο ανεξάρτητους λογαριασμούς σε 25 λεπτά. |
| 9 Σεπτ 14:00 | Το μοντέλο γίνεται private. HTTP 400. Status page. |
| 9 Σεπτ 14:35 | Root cause: prefill pool < context length. |
| 9 Σεπτ 14:52 | Όλα τα prefill nodes με διορθωμένο config. |
| 9 Σεπτ 19:04 | Full rebuild: σωστό pool + engine patch που επιστρέφει error σε rejected requests. |
| 9 Σεπτ 19:40 | Το μοντέλο επανέρχεται δημόσια. |
| 10 Σεπτ | Συνάντηση με maintainers SGLang. |
| 16 Σεπτ – 12 Οκτ | Upstream merges: admission fix, checksums, deferred KV release by default. |
| 19 Οκτ | SGLang v0.5.22. |
| 26 Οκτ | Συντονισμένη δημοσίευση με ερευνητή και RadixArk. |
Αποκατάσταση
Δύο άξονες, και οι δύο απαραίτητοι:
- Το pool να χωράει όλο το context. Η ρύθμιση ευθυγραμμίστηκε με το GLM-5.2. Το prefill KV pool πήγε περίπου στα 2,04 εκατ. tokens, σχεδόν διπλάσιο από το context 1.048.576. Έτσι το rejection path δεν αγγίζεται για έγκυρο request.
- Το rejection path να είναι ασφαλές. Request με pending rejection αποσύρεται στην disaggregation admission queue, με το αρχικό σφάλμα, πριν από bootstrap, allocation ή KV transfer. Το decode επαληθεύει ότι τα tokens που μεταφέρθηκαν ταιριάζουν με όσα δέσμευσε.
Σχετικά upstream: PR #38704 (Cloudflare draft), ήδη στο main ως #36988 (6 Σεπτ, άλλο failure path), και #38935 που απορρίπτει νωρίτερα. Σύσταση Cloudflare: SGLang v0.5.22 ή νεότερο.
Επιπλέον hardening σε όλα τα disaggregated deployments: deferred KV release και στα prefill source pages, bounded Mooncake transfer batches, load balancer που δεν κάνει abort στη μέση του transfer όταν φεύγει ο client, και υποχρεωτικός έλεγχος pool-vs-context πριν από κάθε αλλαγή deployment.
Τι να κάνουν άλλοι operators
Αν τρέχετε SGLang σε disaggregated prefill/decode:
- Μετρήστε το KV pool και συγκρίνετέ το με το context length σε κάθε prefill και decode node, από το startup log, μετά από κάθε αλλαγή weights, quantization, parallelism ή memory fraction. Αν το pool είναι μικρότερο, κατεβάστε το context.
- Αναβαθμίστε σε build που περιλαμβάνει τα #36988 και #38935 (v0.5.22+).
- Deferred KV release και στα δύο roles. Περιορίστε τα Mooncake transfer batches.
- Ενεργοποιήστε ανίχνευση διαφθοράς όπου το μοντέλο το υποστηρίζει (--disaggregation-enable-kv-checksum, --kv-canary) και επιβεβαιώστε από τα logs ότι όντως γίνεται verify.
- Μην αφήνετε το proxy να γεννά άσκοπα aborts πριν το πρώτο token.
Μεγαλύτερη εικόνα
Η Cloudflare περιγράφει μια οικογένεια bugs ιδιοκτησίας KV σελίδων: σελίδα απελευθερώνεται, ξαναδίνεται ή διαβάζεται ενώ κάτι άλλο την κρατάει ακόμα. Δύο συχνές αιτίες: lifetime μέσα σε έναν κόμβο (generation, offload, abort paths) και race ανάμεσα σε κόμβους όταν γίνεται abort ενώ το RDMA γράφει ακόμα.
Μακροπρόθεσμα θέλουν integrity by construction: κάθε φυσική σελίδα να έχει tag που αλλάζει στο reallocation, κάθε request να κρατά τα tags που περιμένει, και ο έλεγχος να γίνεται πριν το decode διαβάσει το cache. Πρωτότυπο του καλοκαιριού είχε κόστος κάτω από 1% σε throughput. Θέλουν επίσης formal verification του RDMA KV transfer protocol (Mooncake), στο πνεύμα δουλειάς όπως Topaz και Meerkat.
Για το blog: αυτό δεν είναι «το μοντέλο έστειλε δεδομένα στην Κίνα». Είναι αποτυχία isolation σε shared GPU memory ενός inference stack. Το μάθημα είναι βαρετό και σημαντικό: μέτρα το pool, μην εμπιστεύεσαι το HTTP 200, και μην θεωρείς το KV cache ιδιωτικό αν οι σελίδες δεν μηδενίζονται.
Πηγές
- Cloudflare: Cross-request KV cache exposure in GLM-5.3
- #36988, #38935, #38704 — ενημέρωση σε v0.5.22+
- Cloudflare Blog