{"record":{"id":"b24a078e95765c0d","repo":"Hmbown/CodeWhale","slug":"codewhale-owned-xai-oauth-dacl-must-grant-only-one","errorCode":null,"errorMessage":"Codewhale-owned xAI OAuth DACL must grant only one user","messagePattern":"Codewhale-owned xAI OAuth DACL must grant only one user","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/xai_credentials.rs","lineNumber":1383,"sourceCode":"    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.\n    let entry = unsafe { &*entries };\n    let trustee_sid: PSID = entry.Trustee.ptstrName.cast();\n    anyhow::ensure!(\n        entry.Trustee.TrusteeForm == TRUSTEE_IS_SID\n            && !trustee_sid.is_null()\n            && unsafe { EqualSid(trustee_sid, user.sid()) } != 0\n            && matches!(entry.grfAccessMode, SET_ACCESS | GRANT_ACCESS)\n            && entry.grfAccessPermissions == FILE_ALL_ACCESS,\n        \"Codewhale-owned xAI OAuth DACL is not current-user-only\"\n    );\n    Ok(())\n}\n\n#[cfg(windows)]","sourceCodeStart":1365,"sourceCodeEnd":1401,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/config/src/xai_credentials.rs#L1365-L1401","documentation":"The verifier enumerates the DACL's explicit entries with GetExplicitEntriesFromAclW and requires exactly one ACE. Credentials written by older versions (before the protected owner-only DACL) can carry inherited or additional entries, and manual icacls grants also add entries, so the strict one-entry policy fails closed on them.","triggerScenarios":"Upgrading codewhale over credentials created by an older version without PROTECTED_DACL; icacls grants to groups or other users; inherited ACEs leaking from a permissive parent directory.","commonSituations":"Version upgrades tightening the security policy; shared machines where an admin granted another account access to the home directory.","solutions":["Recreate the credentials: delete the contents of $CODEWHALE_HOME/credentials and run codewhale auth xai-device","Or normalize the ACL: icacls <path> /inheritance:r then icacls <path> /grant:r \"%USERNAME%:(OI)(CI)F\"","Audit first with icacls <path> to see which extra entries exist"],"exampleFix":":: before\nicacls \"%USERPROFILE%\\.codewhale\\credentials\"   :: multiple ACEs\n\n:: after\nicacls \"%USERPROFILE%\\.codewhale\\credentials\" /inheritance:r\nicacls \"%USERPROFILE%\\.codewhale\\credentials\" /grant:r \"%USERNAME%:(OI)(CI)F\"","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match login() {\n    Ok(v) => v,\n    Err(e) if e.to_string().contains(\"DACL must grant only one user\") => {\n        reset_acl_to_owner_only(&credentials_dir)?; // icacls /inheritance:r + /grant:r user\n        login()?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["After upgrading codewhale, delete and recreate credentials if strict DACL checks fire","Do not grant additional accounts access to the credentials directory","Audit with icacls whenever shared-machine policies touch the home directory"],"tags":["windows","security","acl","permissions","xai-oauth"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}