{"record":{"id":"62eef92b0b9552f4","repo":"Hmbown/CodeWhale","slug":"refusing-non-regular-or-reparse-point-config-lock","errorCode":null,"errorMessage":"refusing non-regular or reparse-point config lock at {}","messagePattern":"refusing non-regular or reparse-point config lock at (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/config_document.rs","lineNumber":253,"sourceCode":"    use std::ffi::OsString;\n    use std::os::windows::ffi::OsStringExt as _;\n    use std::os::windows::fs::MetadataExt as _;\n    use std::os::windows::io::AsRawHandle as _;\n    use windows_sys::Win32::Storage::FileSystem::{\n        FILE_ATTRIBUTE_REPARSE_POINT, FILE_NAME_NORMALIZED, GetFinalPathNameByHandleW,\n        VOLUME_NAME_DOS,\n    };\n\n    let metadata = file.metadata().with_context(|| {\n        format!(\n            \"failed to inspect config lock at {}\",\n            crate::quote_os_path(expected_path)\n        )\n    })?;\n    if !metadata.file_type().is_file()\n        || metadata.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT != 0\n    {\n        bail!(\n            \"refusing non-regular or reparse-point config lock at {}\",\n            crate::quote_os_path(expected_path)\n        );\n    }\n\n    let handle = file.as_raw_handle();\n    let flags = FILE_NAME_NORMALIZED | VOLUME_NAME_DOS;\n    // SAFETY: `handle` remains owned by `file`; a null output buffer asks for\n    // the required UTF-16 length.\n    let needed = unsafe { GetFinalPathNameByHandleW(handle, std::ptr::null_mut(), 0, flags) };\n    if needed == 0 {\n        return Err(std::io::Error::last_os_error()).with_context(|| {\n            format!(\n                \"failed to resolve config lock at {}\",\n                crate::quote_os_path(expected_path)\n            )\n        });\n    }","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/config_document.rs#L235-L271","documentation":"Windows-only safety check in validate_windows_lock_handle (part of the config write-lock path). Before using the lock file handle, its metadata is inspected: if the path is not a regular file or carries the FILE_ATTRIBUTE_REPARSE_POINT flag (symlink/junction/mount point), the lock is refused to prevent lock-file redirection attacks or locking an unintended target.","triggerScenarios":"Acquiring the config write lock on Windows when the lock file path resolves to a reparse point — e.g. the lock file is a symlink, the config directory is a junction, or a sync tool (Dropbox/OneDrive) replaced the file with a placeholder.","commonSituations":"Config directory symlinked to another location; cloud-sync placeholders standing in for real files; a malicious or accidental reparse-point planted at the lock path.","solutions":["Remove the symlink/junction at the lock path so a real regular file can be created there.","Move the config out of a cloud-synced directory or exclude it from sync placeholders.","Point the config directory at a local path instead of a symlinked/junctioned location.","Verify with `dir /AL` (or `fsutil reparsepoint query`) that the lock path is no longer a reparse point, then retry."],"exampleFix":"// before (lock path is a symlink)\nC:\\Users\\me\\.codewhale\\config.lock -> D:\\sync\\config.lock\n// after (regular file, no reparse point)\nfsutil reparsepoint delete C:\\Users\\me\\.codewhale\\config.lock\ndel C:\\Users\\me\\.codewhale\\config.lock  # recreated as a real file on next run","handlingStrategy":"validation","validationCode":"// PowerShell: ensure the config lock path is a regular file, not a reparse point\n$lock = \"$env:USERPROFILE\\.codewhale\\config.lock\"\nif (Test-Path $lock) {\n  $item = Get-Item $lock -Force\n  if ($item.Attributes -band [IO.FileAttributes]::ReparsePoint) {\n    throw \"$lock is a symlink/junction; remove it before running\"\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Do not symlink or junction the config directory or its lock file.","Exclude the config directory from cloud-sync tools that create reparse-point placeholders.","Keep config under a plain local path (e.g. %USERPROFILE%\\.codewhale).","If the lock file looks suspicious, delete it and let the app recreate a real file."],"tags":["config","windows","security","symlink"],"backgroundTag":"path-traversal-blocked","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}