Uz macOS vienu un to pašu failu var nosaukt vairākos veidos, kas baitu līmenī atšķiras, bet diskā norāda uz vienu inode. Divi plaši lietoti JavaScript rīki šo pieņēmumu pārkāpa un ielaida drošības kļūdas. Deno atļauju sistēma (--deny-read un radinieki) tika apieta, jo salīdzināja ceļus pa baitiem; node-tar arhīvu izpakotājs saņēma sacīkstes stāvokli, kas ļauj pārrakstīt patvaļīgus failus.
Abas kļūdas izriet no vienas un tās pašas macOS īpatnības: APFS failu sistēma normalizē un ignorē reģistru, tāpēc passwörter.txt un PASSWÖRTER.txt ir viens fails, bet programmai, kas skatās tikai uz baitiem, tie izskatās pēc diviem dažādiem ceļiem.
Kā APFS saplūdina failu nosaukumus
Burtu ö Unicode var uzrakstīt divējādi. Vienā kodpunktā (U+00F6, forma NFC) vai kā parasto o plus kombinējamo diakritisko zīmi U+0308 (forma NFD). Cilvēkam un ekrānam tas ir viens burts; baitu virknē tie ir dažādi. macOS APFS abas formas uzskata par vienu nosaukumu. Tam klāt nāk reģistrjutības trūkums pēc noklusējuma (a = A) un ligatūras: fi sakrīt ar fi, vācu ß ar ss.
Programma, kas grib atļaut vai liegt piekļuvi konkrētam failam, tāpēc nedrīkst salīdzināt ceļa baitus. Tai jājautā failu sistēmai, uz kuru inode ceļš noved, vai jānormalizē tieši tā, kā to dara pati sistēma. Deno un node-tar to nedarīja.
Deno: atļauju pārbaude pa baitiem
Deno pārdošanas arguments ir smilškaste — skripts neko nelasa un neizpilda, ja tu to skaidri neatļauj. Atļauju karogi --deny-read, --deny-write, --deny-run un --deny-ffi salīdzināja pieprasīto ceļu ar liegto pēc neapstrādātiem baitiem. Uz macOS tas nozīmēja, ka aizsardzību var apiet, tikai pierakstot to pašu nosaukumu citādi.
Piemērs no GitLab drošības brīdinājuma par CVE-2026-49401: ar --deny-read=/secrets/passwörter.txt skripts joprojām varēja nolasīt failu, atverot /secrets/passwo{U+0308}rter.txt (NFD vietā NFC) vai /SECRETS/PASSWÖRTER.txt ar citu reģistru. Liegtais un pieprasītais ceļš baitu līmenī atšķīrās, tāpēc pārbaude izlaida cauri; kodols pēc tam abus izšķīra uz vienu inode un failu atdeva. Visi četri karogi dala vienu ceļa salīdzināšanas kodu, tāpēc kļūda skāra tos visus.
Novērtējums ir CVSS 5.2 (vidējs), jo uzbrukumam vajag lokālu piekļuvi un jau palaistu skriptu. Kļūda salabota Deno 2.7.14. Klasifikācija — CWE-176 (nepareiza Unicode kodējuma apstrāde) un CWE-41 (nepareiza ceļu ekvivalences izšķiršana).
node-tar: sacīkste un simlinku saindēšana
node-tar tā pati Unicode nesakritība izpaudās bīstamāk. Bibliotēka izmanto mehānismu PathReservations, kas sakārto rindā darbības ar vienu ceļu, lai divas paralēlas operācijas nesabojātu viena otru. Rezervācijas salīdzināja ceļus NFD formā, kur ß un ss ir dažādi. Failu sistēmā, kas normalizāciju ignorē, sadursmīgie ceļi rindā vairs nesakārtojas pareizi, un rodas time-of-check-time-of-use plaisa.
Sekas apraksta Ubuntu drošības ieraksts par CVE-2026-23950: ļaunprātīgs tar arhīvs ar īpaši veidotiem Unicode nosaukumiem var izsist simboliskās saites aizsardzību un pārrakstīt failus ārpus mērķa mapes. Novērtējums ir 8.8 (augsts), attālināti izmantojams, jo pietiek ar to, ka upuris izpako svešu arhīvu. Skartas versijas līdz 7.5.3, labojums 7.5.4.
Labojums neaprobežojas ar vienu normalizācijas izsaukumu. node-tar tagad normalizē formā, kas atbilst mērķa failu sistēmai (piemēram, NFKD), un pēc tam secīgi lieto
toLocaleLowerCase('en')untoLocaleUpperCase('en'), lai reģistrs un ligatūras saplūst tāpat kā diskā.
Kāpēc tas atkārtojas
Abas kļūdas nāk no viena maldīga pieņēmuma: ka faila nosaukums ir vienkārša baitu virkne un divas atšķirīgas virknes ir divi atšķirīgi faili. Uz Linux ext4 tas parasti tā arī ir. Uz macOS APFS un vecākas HFS+ tā nav, un tāpat rīkojas Windows NTFS ar savu reģistrjutības trūkumu. Kods, kas drošības lēmumu balsta uz virkņu salīdzināšanu, uz šīm sistēmām pieļaus kļūdu.
Drošs ceļš ir pieņemt lēmumu pēc tā, uz ko ceļš faktiski noved — pēc inode vai kanoniskā ceļa, ko atgriež pati sistēma (realpath, faila deskriptors), nevis pēc teksta, ko padeva lietotājs. Ja tas nav iespējams, normalizācijai jāatkārto konkrētās failu sistēmas uzvedība, ieskaitot reģistru un ligatūras.
Ko darīt tagad
Atjaunini Deno uz 2.7.14 vai jaunāku un node-tar uz 7.5.4 vai jaunāku; pārbaudi arī tranzitīvās atkarības, jo node-tar ievelk daudzi npm pakotņu instalētāji. Kamēr nevari atjaunināt node-tar, izfiltrē simboliskās saites no neuzticamiem arhīviem izpakošanas laikā. Deno lietotājiem uz macOS ir vērts atcerēties, ka --deny-* karogi pirms labojuma nedeva to garantiju, kādu solīja.
Avoti
- GitLab Advisory Database — CVE-2026-49401: Deno Permission Bypass via Unicode Normalization Mismatch on macOS (APFS)
- cvefeed.io — CVE-2026-23950: node-tar Race Condition in Path Reservations via Unicode Ligature Collisions on macOS APFS
- Ubuntu Security — CVE-2026-23950
- Deno Docs — Security and permissions
Komentāri
Šim rakstam vēl nav komentāru. Esi pirmais, kurš dalās ar savu viedokli.