Hmbown/CodeWhale · critical

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

validate_private_basename requires the name to be exactly one normal, UTF-8 path component — no separators, no parent refs, and byte-identical to its own file_name. This blocks path traversal and non-UTF-8 tricks in low-level raw file operations.

Solutions

  1. Pass only a bare file name with no separators; build full paths via the store, not the caller.
  2. Sanitize/validate user input before it reaches these APIs (reject any name containing a path separator).
  3. Use path_for or validate_owned_auth_name first to map logical names to legal basenames.
  4. If handling untrusted names, reject early in your own layer with a clear message.

Example fix

// before
store.remove_raw("../escaped.json")?; // traversal attempt
// after
let name = "xai.oauth.v2.retired.json";
assert_eq!(Path::new(name).components().count(), 1);
store.remove_raw(name)?;
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

fn is_single_normal_component(name: &str) -> bool {
    !name.contains('/') && !name.contains('\\') && name != ".." && !name.is_empty()
}

Prevention

When it happens

Trigger: Calling open_at, remove_raw, rename_raw, or the internal/windows file openers with a name containing '/', '\\', '..', an interior NUL pattern, non-UTF-8 bytes, or any multi-component path.

Common situations: Passing a relative subpath like "sub/dir/file.json"; user-controlled input reaching the name parameter (path traversal attempt); platform path separators slipping in from concatenation code.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/cda98eb44b89f19a. Report an issue: GitHub.

Appendix: source

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

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

fn is_chatgpt_owned_auth_name(name: &str) -> bool {
    name == LEGACY_CHATGPT_OAUTH_FILE_NAME || is_valid_chatgpt_oauth_generation(name)
}

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 73e0f67d83)