{"record":{"id":"7981e0cc0912adad","repo":"Hmbown/CodeWhale","slug":"codewhale-owned-xai-oauth-storage-must-have-an-own","errorCode":null,"errorMessage":"Codewhale-owned xAI OAuth storage must have an owner-only DACL","messagePattern":"Codewhale-owned xAI OAuth storage must have an owner-only DACL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/xai_credentials.rs","lineNumber":1369,"sourceCode":"            SE_FILE_OBJECT,\n            OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,\n            &mut owner,\n            std::ptr::null_mut(),\n            &mut dacl,\n            std::ptr::null_mut(),\n            &mut descriptor,\n        )\n    };\n    if result != ERROR_SUCCESS {\n        return Err(std::io::Error::from_raw_os_error(result as i32))\n            .context(\"reading Codewhale-owned xAI OAuth security descriptor\");\n    }\n    let _descriptor = WindowsLocalAllocation(descriptor.cast());\n    anyhow::ensure!(\n        !owner.is_null() && unsafe { EqualSid(owner, user.sid()) } != 0,\n        \"Codewhale-owned xAI OAuth storage owner is not the current user\"\n    );\n    anyhow::ensure!(\n        !dacl.is_null(),\n        \"Codewhale-owned xAI OAuth storage must have an owner-only DACL\"\n    );\n    let mut count = 0;\n    let mut entries: *mut EXPLICIT_ACCESS_W = std::ptr::null_mut();\n    // SAFETY: `dacl` belongs to the live descriptor; Windows allocates the\n    // returned entry array, released by the guard below.\n    let result = unsafe { GetExplicitEntriesFromAclW(dacl, &mut count, &mut entries) };\n    if result != ERROR_SUCCESS {\n        return Err(std::io::Error::from_raw_os_error(result as i32))\n            .context(\"reading Codewhale-owned xAI OAuth DACL entries\");\n    }\n    let _entries = WindowsLocalAllocation(entries.cast());\n    anyhow::ensure!(\n        count == 1 && !entries.is_null(),\n        \"Codewhale-owned xAI OAuth DACL must grant only one user\"\n    );\n    // SAFETY: `count == 1` proves the first returned entry is initialized.","sourceCodeStart":1351,"sourceCodeEnd":1387,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/config/src/xai_credentials.rs#L1351-L1387","documentation":"verify_windows_owner_only_handle requires a non-NULL DACL on every secured handle. A NULL DACL on Windows grants everyone full access, so the store refuses it outright. GetSecurityInfo returns a NULL DACL on filesystems without ACL support, most commonly FAT32/exFAT volumes.","triggerScenarios":"$CODEWHALE_HOME redirected to a FAT32/exFAT USB or SD drive; any object whose DACL was removed by low-level tooling.","commonSituations":"Portable/USB home directories; exFAT-formatted secondary drives used for profiles; embedded volumes.","solutions":["Move CODEWHALE_HOME to an NTFS volume (e.g. under the real user profile) and re-run codewhale auth xai-device","Reformat the target volume as NTFS if it must host the home directory","Do not copy old files over; authenticate again so the store creates properly secured storage"],"exampleFix":":: before\nset CODEWHALE_HOME=E:\\codewhale   (E: is FAT32/exFAT)\n\n:: after\nset CODEWHALE_HOME=%USERPROFILE%\\.codewhale\ncodewhale auth xai-device","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"if let Err(e) = login() {\n    if e.to_string().contains(\"must have an owner-only DACL\") {\n        // FAT/exFAT cannot store ACLs: fall back to an NTFS-backed home\n        std::env::set_var(\"CODEWHALE_HOME\", ntfs_home.display().to_string());\n        return login();\n    }\n    return Err(e);\n}","preventionTips":["Never place CODEWHALE_HOME on FAT32/exFAT media","Check the volume format (fsutil fsinfo volumeinfo X:) before redirecting home","Re-authenticate after moving home; do not copy credential files over"],"tags":["windows","security","acl","filesystem","xai-oauth"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}