* Detects suspicious Windows path patterns that could bypass security checks. * These patterns include: * - NTFS Alternate Data Streams (e.g., file.txt::$DATA or file.txt:stream) * - 8.3 short names (e.g., GIT~1, CLAUDE~1, SETTIN~1.JSON) * - Long path prefixes (e.g., \\?\C:\..., \\.\C:\..., //?/
(path: string)
| 545 | * @returns true if suspicious Windows path patterns are detected |
| 546 | */ |
| 547 | function hasSuspiciousWindowsPathPattern(path: string): boolean { |
| 548 | // Check for NTFS Alternate Data Streams |
| 549 | // Look for ':' after position 2 to skip drive letters (e.g., C:\) |
| 550 | // Examples: file.txt::$DATA, .bashrc:hidden, settings.json:stream |
| 551 | // Note: ADS colon syntax is only interpreted by the Windows kernel. On WSL, |
| 552 | // DrvFs mounts route file operations through the Windows kernel, so colon |
| 553 | // syntax is still interpreted as ADS separators. On Linux/macOS (non-WSL), |
| 554 | // even when NTFS is mounted, ADS is accessed via xattrs (ntfs-3g) not colon |
| 555 | // syntax, and colons are valid filename characters. |
| 556 | if (getPlatform() === 'windows' || getPlatform() === 'wsl') { |
| 557 | const colonIndex = path.indexOf(':', 2) |
| 558 | if (colonIndex !== -1) { |
| 559 | return true |
| 560 | } |
| 561 | } |
| 562 | |
| 563 | // Check for 8.3 short names |
| 564 | // Look for '~' followed by a digit |
| 565 | // Examples: GIT~1, CLAUDE~1, SETTIN~1.JSON, BASHRC~1 |
| 566 | if (/~\d/.test(path)) { |
| 567 | return true |
| 568 | } |
| 569 | |
| 570 | // Check for long path prefixes (both backslash and forward slash variants) |
| 571 | // Examples: \\?\C:\Users\..., \\.\C:\..., //?/C:/..., //./C:/... |
| 572 | if ( |
| 573 | path.startsWith('\\\\?\\') || |
| 574 | path.startsWith('\\\\.\\') || |
| 575 | path.startsWith('//?/') || |
| 576 | path.startsWith('//./') |
| 577 | ) { |
| 578 | return true |
| 579 | } |
| 580 | |
| 581 | // Check for trailing dots and spaces that Windows strips during path resolution |
| 582 | // Examples: .git., .claude , .bashrc..., settings.json. |
| 583 | // This can bypass string matching if ".git" is blocked but ".git." is used |
| 584 | if (/[.\s]+$/.test(path)) { |
| 585 | return true |
| 586 | } |
| 587 | |
| 588 | // Check for DOS device names that Windows treats as special devices |
| 589 | // Examples: .git.CON, settings.json.PRN, .bashrc.AUX |
| 590 | // Device names: CON, PRN, AUX, NUL, COM1-9, LPT1-9 |
| 591 | if (/\.(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i.test(path)) { |
| 592 | return true |
| 593 | } |
| 594 | |
| 595 | // Check for three or more consecutive dots (...) when used as a path component |
| 596 | // This pattern can be used to bypass security checks or create confusion |
| 597 | // Examples: .../file.txt, path/.../file |
| 598 | // Only block when dots are preceded AND followed by path separators (/ or \) |
| 599 | // This allows legitimate uses like Next.js catch-all routes [...]name] |
| 600 | if (/(^|\/|\\)\.{3,}(\/|\\|$)/.test(path)) { |
| 601 | return true |
| 602 | } |
| 603 | |
| 604 | // Check for UNC paths (on all platforms for defense-in-depth) |
no test coverage detected