Hmbown/CodeWhale · critical
Codewhale-owned xAI OAuth storage must have an owner-only…
Error message
Codewhale-owned xAI OAuth storage must have an owner-only DACL
What it means
Windows-only security check in verify_windows_owner_only_handle (crates/config/src/xai_credentials.rs). After opening the xAI OAuth storage object, Codewhale reads its security descriptor and requires a non-null owner plus a DACL; if the DACL pointer is null the handle's security is unverifiable as owner-only, so the store refuses to use it. This guards secret material from being stored on an object with no access-control list (which on Windows can default to inherited/unrestricted access).
Solutions
- Delete the existing xAI OAuth storage directory (e.g. the codewhale xai credentials folder under the user profile) and let the app recreate and re-provision it, then log in again.
- Reset the ACL explicitly: icacls "<path>" /reset, or remove inheritance with /inheritance:r and grant only the current user full control.
- Check that no external sync/AV tool is rewriting ACLs on the profile directory; exclude the credentials path.
- If this fires on freshly created storage, report a bug: object provisioning failed to attach the owner-only DACL.
Example fix
// before: directory copied from backup has a NULL DACL // icacls "%APPDATA%\codewhale\xai" -> DACL absent // after icacls "%APPDATA%\codewhale\xai" /inheritance:r /grant:r "%USERNAME%":F
Defensive patterns
Strategy: validation
Validate before calling
// Windows, before opening the store
use windows::Win32::Security::GetNamedSecurityInfoW;
let psd = GetNamedSecurityInfoW(&path_as_wide, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, None, None, None, None, None)?;
let dacl = psd.dacl();
if dacl.is_none() {
// repair: remove inheritance, grant current user full control
run("icacls <path> /inheritance:r /grant:r %USERNAME%:F")?;
} Prevention
- Never copy or restore the credentials directory with sync/backup tools that drop ACLs; re-create it via the app instead.
- Exclude the credentials path from corporate ACL-hardening and profile-cleanup scripts.
- Verify with icacls after any manual ACL surgery that the DACL is a single current-user grant.
When it happens
Trigger: Calling XaiOAuthCredentialStore::open (via open_owned_credentials_directory), validate_owned_file_handle, or the test windows_store_secures_every_new_owned_object_for_the_current_user on Windows when GetSecurityInfo returns a descriptor whose DACL is NULL — e.g. the directory/file was created outside the crate's owner-only provisioning (copied from a backup, created by another tool, or DACL inheritance stripped).
Common situations: A user restores the Codewhale credentials directory from a backup or sync tool (Dropbox/OneDrive) that recreated it without the original ACL; a corporate profile-cleanup tool resets ACLs; a previous version of the app or a manual mkdir created the path without the owner-only DACL.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Codewhale-owned credential file DACL must grant only one…
- Codewhale-owned credential file must have an owner-only DACL
- Codewhale-owned xAI OAuth DACL is not current-user-only
- Codewhale-owned xAI OAuth DACL must grant only one user
- Codewhale-owned credential file DACL is not…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/7981e0cc0912adad.
Report an issue: GitHub.
Appendix: source
Thrown at crates/config/src/xai_credentials.rs:1506
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
&mut owner,
std::ptr::null_mut(),
&mut dacl,
std::ptr::null_mut(),
&mut descriptor,
)
};
if result != ERROR_SUCCESS {
return Err(std::io::Error::from_raw_os_error(result as i32))
.context("reading Codewhale-owned xAI OAuth security descriptor");
}
let _descriptor = WindowsLocalAllocation(descriptor.cast());
// SAFETY: `owner` is non-null; `user.sid()` is owned by `user`.
anyhow::ensure!(
!owner.is_null() && unsafe { EqualSid(owner, user.sid()) } != 0,
"Codewhale-owned xAI OAuth storage owner is not the current user"
);
anyhow::ensure!(
!dacl.is_null(),
"Codewhale-owned xAI OAuth storage must have an owner-only DACL"
);
let mut count = 0;
let mut entries: *mut EXPLICIT_ACCESS_W = std::ptr::null_mut();
// SAFETY: `dacl` belongs to the live descriptor; Windows allocates the
// returned entry array, released by the guard below.
let result = unsafe { GetExplicitEntriesFromAclW(dacl, &mut count, &mut entries) };
if result != ERROR_SUCCESS {
return Err(std::io::Error::from_raw_os_error(result as i32))
.context("reading Codewhale-owned xAI OAuth DACL entries");
}
let _entries = WindowsLocalAllocation(entries.cast());
anyhow::ensure!(
count == 1 && !entries.is_null(),
"Codewhale-owned xAI OAuth DACL must grant only one user"
);
// SAFETY: `count == 1` proves the first returned entry is initialized.View on GitHub (pinned to 73e0f67d83)