Hmbown/CodeWhale · error · anyhow::Error

xAI OAuth private basename must be one UTF-8 path component

Error message

xAI OAuth private basename must be one UTF-8 path component

What it means

Enforced by validate_private_basename before every raw openat/renameat/unlinkat (open_at, remove_raw, rename_raw, open_windows_file): the name must be exactly one Normal UTF-8 path component with no separators and not `.`/`..`. This guarantees the *at() calls cannot escape the pinned credentials directory. Public entry points funnel input through validate_owned_auth_name first, so hitting this means an in-crate caller passed a compound or non-UTF-8 name.

Source

Thrown at crates/config/src/xai_credentials.rs:440

            if store.remove_raw(&target)? {
                removed += 1;
            }
        }
        Ok(removed)
    }
}

fn validate_owned_auth_name(name: &str) -> Result<()> {
    anyhow::ensure!(
        name == LEGACY_XAI_OAUTH_FILE_NAME || is_valid_xai_oauth_generation(name),
        "invalid Codewhale-owned xAI OAuth basename"
    );
    Ok(())
}

fn validate_private_basename(name: &str) -> Result<()> {
    let path = Path::new(name);
    anyhow::ensure!(
        path.components().count() == 1
            && matches!(path.components().next(), Some(Component::Normal(_)))
            && path.file_name().and_then(|value| value.to_str()) == Some(name),
        "xAI OAuth private basename must be one UTF-8 path component"
    );
    Ok(())
}

#[cfg(unix)]
fn open_owned_credentials_directory(directory: &Path) -> Result<XaiOAuthCredentialStore> {
    use std::os::fd::FromRawFd as _;
    use std::os::unix::fs::{MetadataExt as _, PermissionsExt as _};

    anyhow::ensure!(
        directory.is_absolute(),
        "xAI OAuth credentials directory must be absolute"
    );
    // SAFETY: the literal root path contains no interior NUL and the returned

View on GitHub (pinned to 8880682c63)

Solutions

  1. Pass a single basename (no '/', '\\', '.', or '..') to internal store helpers
  2. Route new public entry points through validate_owned_auth_name and keep validate_private_basename on the private raw layer
  3. In tests, build names with the same helper functions the production code uses
Defensive patterns

Strategy: validation

Validate before calling

fn is_single_component(name: &str) -> bool {
    let p = std::path::Path::new(name);
    p.components().count() == 1
        && matches!(p.components().next(), Some(std::path::Component::Normal(_)))
        && p.file_name().and_then(|n| n.to_str()) == Some(name)
}

Type guard

fn is_private_basename(name: &str) -> bool {
    !name.is_empty()
        && !name.contains(['/', '\\', '\u{0}'])
        && name != "."
        && name != ".."
        && std::path::Path::new(name).file_name().and_then(|n| n.to_str()) == Some(name)
}

Prevention

When it happens

Trigger: Calling the private rename_raw/remove_raw/open_at helpers with names like "dir/xai-auth.json", "..", ".", or a non-UTF-8 OsStr name; only reachable from code inside the codewhale-config crate or its unit tests.

Common situations: Contributors extending the store (new lifecycle files, tombstones) passing full paths instead of basenames; refactors that bypass validate_owned_auth_name; fuzz tests feeding path-shaped strings into internal helpers.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/cda98eb44b89f19a. Report an issue: GitHub.