{"record":{"id":"d93e9ececf7513b6","repo":"Hmbown/CodeWhale","slug":"refusing-non-loopback-app-server-bind-without-expl","errorCode":null,"errorMessage":"refusing non-loopback app-server bind without explicit auth token; pass --auth-token or set CODEWHALE_APP_SERVER_TOKEN","messagePattern":"refusing non-loopback app-server bind without explicit auth token; pass --auth-token or set CODEWHALE_APP_SERVER_TOKEN","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/app-server/src/lib.rs","lineNumber":701,"sourceCode":"fn resolve_auth_token(options: &AppServerOptions) -> Result<Option<String>> {\n    let configured = options.auth_token.as_ref().map(|token| token.trim());\n    if let Some(token) = configured\n        && token.is_empty()\n    {\n        bail!(\"app-server auth token cannot be empty\");\n    }\n    let has_explicit_token = configured.is_some();\n\n    if options.insecure_no_auth {\n        if !options.listen.ip().is_loopback() {\n            bail!(\"refusing unauthenticated app-server bind on non-loopback address\");\n        }\n        eprintln!(\"warning: app-server HTTP auth disabled by --insecure-no-auth\");\n        return Ok(None);\n    }\n\n    if !has_explicit_token && !options.listen.ip().is_loopback() {\n        bail!(\n            \"refusing non-loopback app-server bind without explicit auth token; pass --auth-token or set CODEWHALE_APP_SERVER_TOKEN\"\n        );\n    }\n\n    let token = configured\n        .map(str::to_string)\n        .unwrap_or_else(|| format!(\"cwapp_{}\", Uuid::new_v4().simple()));\n    for line in app_server_auth_status_lines(has_explicit_token) {\n        eprintln!(\"{line}\");\n    }\n    Ok(Some(token))\n}\n\nfn app_server_auth_status_lines(has_explicit_token: bool) -> Vec<&'static str> {\n    if has_explicit_token {\n        return vec![\"app-server auth: bearer token required for HTTP routes.\"];\n    }\n    vec![","sourceCodeStart":683,"sourceCodeEnd":719,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/app-server/src/lib.rs#L683-L719","documentation":"open_bundle_directory opens a plugin bundle directory on Windows with BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT and deny-write sharing, then requires the handle to be a real directory without the reparse attribute. A junction or directory-symlink, or a path that actually names a file, is rejected with InvalidData.","triggerScenarios":"Reviewing a plugin whose directory is a junction or directory symlink (for example a shared plugins dir linked into multiple installs), or passing a file path where a bundle directory is expected.","commonSituations":"Portable installs sharing one plugins directory via junction; backup restores that materialize directories as links; dedupe tools junctioning large folders.","solutions":["Copy the plugin tree to a real directory instead of junctioning it, and point Codewhale there","Reinstall the plugin so Codewhale stages its own directory","Remove the junction ('rmdir <link>' removes only the link on Windows) and restore a physical directory"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const FILE_ATTRIBUTE_REPARSE_POINT: u32 = 0x400;\n\nfn is_real_directory(path: &std::path::Path) -> bool {\n    match std::fs::symlink_metadata(path) {\n        Ok(md) => md.is_dir() && md.file_attributes() & FILE_ATTRIBUTE_REPARSE_POINT == 0,\n        Err(_) => false,\n    }\n}","typeGuard":"fn is_physical_dir(p: &std::path::Path) -> bool {\n    std::fs::symlink_metadata(p).map(|m| m.is_dir() && m.file_attributes() & 0x400 == 0).unwrap_or(false)\n}","tryCatchPattern":"match open_bundle_directory(&path) {\n    Err(e) if e.to_string().contains(\"reparse point or non-directory\") => {\n        // replace the junction with a copied, real directory and retry\n    }\n    other => other?,\n}","preventionTips":["Copy plugin trees instead of junctioning them between installs","Check 'fsutil reparsepoint query <dir>' when a plugins dir was restored from backup","Keep one plugins directory per installation"],"tags":["plugins","windows","junction","reparse-point","invalid-data"],"backgroundTag":"symlink-in-path","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}