{"record":{"id":"58a2f4a8ef92e001","repo":"ramensoftware/windhawk","slug":"invalid-libraryfilename-value","errorCode":null,"errorMessage":"Invalid LibraryFileName value","messagePattern":"Invalid LibraryFileName value","errorType":"exception","errorClass":"std::runtime_error","httpStatus":null,"severity":"error","filePath":"src/windhawk/engine/mod.cpp","lineNumber":263,"sourceCode":"            listTakesEveryProcess(patterns.include)) ||\n           listTakesEveryProcess(patterns.includeCustom);\n}\n\n// The library named by the mod's settings. It must be a file in the mods\n// folder, so only a bare file name is accepted: a separator, a root name or a\n// \"..\" would make the joined path escape the folder. A ':' is rejected on its\n// own, since a root name is a single drive letter and \"foo:bar\", a stream on\n// the folder, is its own filename().\nstd::filesystem::path GetModLibraryPath(std::wstring_view libraryFileName) {\n    if (libraryFileName.empty()) {\n        throw std::runtime_error(\"Missing LibraryFileName value\");\n    }\n\n    std::filesystem::path fileName(libraryFileName);\n    if (fileName != fileName.filename() ||\n        libraryFileName.find(L':') != libraryFileName.npos ||\n        libraryFileName == L\".\" || libraryFileName == L\"..\") {\n        throw std::runtime_error(\"Invalid LibraryFileName value\");\n    }\n\n    return StorageManager::GetInstance().GetModsPath() / fileName;\n}\n\nMod::ChangeMarker MakeChangeMarker(PortableSettings& settings) {\n    return {\n        .libraryFileName = settings.GetString(L\"LibraryFileName\").value_or(L\"\"),\n        .settingsChangeTime =\n            settings.GetInt(L\"SettingsChangeTime\").value_or(0),\n    };\n}\n\n// Whether the mod's library carries the tool mod marker in its export table.\nbool DoesModExportToolModMarker(PCWSTR modName, PortableSettings& settings) {\n    // A library which can't be read isn't turned into a tool mod; the load path\n    // is what reports such a failure to the user.\n    try {","sourceCodeStart":245,"sourceCodeEnd":281,"githubUrl":"https://github.com/ramensoftware/windhawk/blob/61d99ed8e182e1af1b60109612b6763ad1b4b74e/src/windhawk/engine/mod.cpp#L245-L281","documentation":"GetModLibraryPath rejects a LibraryFileName that is not a bare file name: paths containing separators, drive/root components, a colon, '.' or '..' are refused so the joined path cannot escape the mods storage folder. Any such value throws runtime_error('Invalid LibraryFileName value'). This is a deliberate path-traversal guard.","triggerScenarios":"A mod's LibraryFileName set to something like '..\\\\evil.dll', 'C:\\\\Windows\\\\x.dll', 'sub\\\\mod.dll', 'foo:bar' or '.' — anything whose std::filesystem value differs from its filename() component.","commonSituations":"Malicious or carelessly authored mod packages trying to point outside the mods directory; users copying a full path into LibraryFileName instead of just the DLL name; Windows stream syntax 'name:stream' in the value.","solutions":["Set LibraryFileName to the bare DLL file name only (e.g. LibraryFileName=MyMod.dll) — no paths, drive letters, colons, or '.'/'..'.","Reinstall the mod from its official source if you didn't author the metadata yourself.","If authoring, keep the DLL inside the per-mod folder and reference it by name only."],"exampleFix":"// before\nLibraryFileName=C:\\Users\\me\\build\\MyMod.dll\n// after\nLibraryFileName=MyMod.dll","handlingStrategy":"validation","validationCode":"// caller-side pre-check mirroring the guard\nbool IsBareFileName(std::wstring_view name) {\n    if (name.empty() || name == L\".\" || name == L\"..\") return false;\n    if (name.find(L':') != std::wstring_view::npos) return false;\n    if (name.find(L'\\\\') != std::wstring_view::npos ||\n        name.find(L'/') != std::wstring_view::npos) return false;\n    return true;\n}","typeGuard":"bool IsSafeLibraryFileName(std::wstring_view v) {\n    std::filesystem::path p(v);\n    return !v.empty() && p == p.filename() &&\n           v.find(L':') == std::wstring_view::npos &&\n           v != L\".\" && v != L\"..\";\n}","tryCatchPattern":"try {\n    auto path = GetModLibraryPath(libFile);\n} catch (const std::runtime_error& e) {\n    if (std::string_view(e.what()) == \"Invalid LibraryFileName value\") {\n        LOG(L\"Rejecting mod with unsafe LibraryFileName\");\n    }\n}","preventionTips":["Always store only the bare DLL name in LibraryFileName.","Treat any path-like value in mod metadata as a red flag (possible malicious mod).","Normalize/strip user-supplied paths to filename() before writing metadata.","Keep the traversal guard; never 'fix' errors like this by widening accepted values."],"tags":["windhawk","mod-metadata","path-traversal","validation"],"backgroundTag":"path-traversal-blocked","analyzedSha":"61d99ed8e182e1af1b60109612b6763ad1b4b74e","analyzedAt":"2026-09-12T14:02:41.115Z","contentChangedAt":"2026-09-12T14:02:41.115Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}