{"record":{"id":"e5c79fab9b5adeda","repo":"Hmbown/CodeWhale","slug":"invalid-codewhale-owned-oauth-basename","errorCode":null,"errorMessage":"invalid Codewhale-owned OAuth basename","messagePattern":"invalid Codewhale-owned OAuth basename","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/config/src/xai_credentials.rs","lineNumber":554,"sourceCode":"\n    /// Permanently remove retired bytes after the replacement config commits.\n    pub fn commit(self, store: &XaiOAuthCredentialStore) -> Result<usize> {\n        let mut removed = 0;\n        for (_original, _tombstone) in self.retired {\n            #[cfg(windows)]\n            let target = _original;\n            #[cfg(not(windows))]\n            let target = _tombstone;\n            if store.remove_raw(&target)? {\n                removed += 1;\n            }\n        }\n        Ok(removed)\n    }\n}\n\nfn validate_owned_auth_name(name: &str) -> Result<()> {\n    anyhow::ensure!(\n        name == LEGACY_XAI_OAUTH_FILE_NAME\n            || name == LEGACY_CHATGPT_OAUTH_FILE_NAME\n            || is_valid_xai_oauth_generation(name)\n            || is_valid_chatgpt_oauth_generation(name),\n        \"invalid Codewhale-owned OAuth basename\"\n    );\n    Ok(())\n}\n\nfn is_chatgpt_owned_auth_name(name: &str) -> bool {\n    name == LEGACY_CHATGPT_OAUTH_FILE_NAME || is_valid_chatgpt_oauth_generation(name)\n}\n\nfn validate_private_basename(name: &str) -> Result<()> {\n    let path = Path::new(name);\n    anyhow::ensure!(\n        path.components().count() == 1\n            && matches!(path.components().next(), Some(Component::Normal(_)))","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/config/src/xai_credentials.rs#L536-L572","documentation":"validate_owned_auth_name only accepts the known legacy OAuth file names or well-formed generation names; anything else is rejected. This whitelist prevents arbitrary files in the credentials directory from being read, written, or removed through the store API.","triggerScenarios":"Calling path_for, read_to_string, write, or remove with a name that is neither LEGACY_XAI_OAUTH_FILE_NAME, LEGACY_CHATGPT_OAUTH_FILE_NAME, nor a valid xAI/ChatGPT oauth generation basename.","commonSituations":"A typo in the file name constant; passing a full path instead of a basename; a caller constructing generation names with the wrong prefix or suffix format after a version change.","solutions":["Use the store's documented name constants (e.g. LEGACY_XAI_OAUTH_FILE_NAME) or the path_for helper instead of hand-built strings.","Check the expected generation-name format (prefix/suffix) used by is_valid_xai_oauth_generation / is_valid_chatgpt_oauth_generation.","Strip any directory components; pass only the basename.","If a new file name is genuinely needed, extend the validator rather than bypassing it."],"exampleFix":"// before\nstore.read_to_string(\"tokens.json\")?; // rejected\n// after\nstore.read_to_string(LEGACY_XAI_OAUTH_FILE_NAME)?;","handlingStrategy":"validation","validationCode":"fn is_owned_auth_name(name: &str) -> bool {\n    name == LEGACY_XAI_OAUTH_FILE_NAME || name == LEGACY_CHATGPT_OAUTH_FILE_NAME\n}","typeGuard":"fn is_owned_auth_name(name: &str) -> bool {\n    name == LEGACY_XAI_OAUTH_FILE_NAME\n        || name == LEGACY_CHATGPT_OAUTH_FILE_NAME\n        || name.starts_with(\"xai.oauth.v\")\n        || name.starts_with(\"chatgpt.oauth.v\")\n}","tryCatchPattern":null,"preventionTips":["Always use exported name constants or path_for instead of string literals","Never pass user-supplied strings as the file name","Centralize name construction in one helper"],"tags":["validation","whitelist","credentials","filename"],"backgroundTag":"invalid-argument-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}