{"record":{"id":"cb5a5c6941e298c1","repo":"shadow1ng/fscan","slug":"local-pe-not-specified-cb5a5c","errorCode":null,"errorMessage":"local_pe_not_specified","messagePattern":"local_pe_not_specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/local/winlogon.go","lineNumber":29,"sourceCode":"\t\"strings\"\n\n\t\"github.com/shadow1ng/fscan/common\"\n\t\"github.com/shadow1ng/fscan/common/i18n\"\n\t\"github.com/shadow1ng/fscan/plugins\"\n)\n\ntype WinLogonPlugin struct {\n\tplugins.BasePlugin\n}\n\nfunc NewWinLogonPlugin() *WinLogonPlugin {\n\treturn &WinLogonPlugin{BasePlugin: plugins.NewBasePlugin(\"winlogon\")}\n}\n\nfunc (p *WinLogonPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {\n\tpePath := session.Config.WinPEFile\n\tif pePath == \"\" {\n\t\treturn &plugins.Result{Success: false, Error: fmt.Errorf(\"%s\", i18n.GetText(\"local_pe_not_specified\"))}\n\t}\n\tif _, err := os.Stat(pePath); err != nil {\n\t\treturn &plugins.Result{Success: false, Error: fmt.Errorf(\"%s\", i18n.Tr(\"local_pe_not_found\", pePath))}\n\t}\n\n\tabsPath, _ := filepath.Abs(pePath)\n\tkey := `HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon`\n\n\tentries := []struct {\n\t\tname  string\n\t\tvalue string\n\t\tdesc  string\n\t}{\n\t\t{\"Userinit\", fmt.Sprintf(`C:\\Windows\\system32\\userinit.exe,%s`, absPath), i18n.GetText(\"winlogon_userinit_append\")},\n\t\t{\"Shell\", fmt.Sprintf(`explorer.exe,%s`, absPath), i18n.GetText(\"winlogon_shell_append\")},\n\t}\n\n\tvar output strings.Builder","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/local/winlogon.go#L11-L47","documentation":"WinLogonPlugin.Scan (Winlogon shell/userinit hijack plugin) requires a local PE file path in session.Config.WinPEFile because the Winlogon registry values must reference an executable. If the field is empty, Scan returns a failed Result with the localized \"local_pe_not_specified\" message before any registry modification. This is required-input validation.","triggerScenarios":"Scan is invoked while session.Config.WinPEFile == \"\" — the winlogon plugin was enabled without the local PE path being set in the scan configuration.","commonSituations":"Forgot the --winpe-file flag when enabling winlogon, config file from another profile lacking the key, or a version change renamed the config field so the old key is ignored.","solutions":["Set the config option that populates session.Config.WinPEFile (e.g., --winpe-file <path>) before running the winlogon plugin.","Confirm the active config file/profile actually contains the key.","When calling Scan programmatically, assign the absolute PE path to session.Config.WinPEFile first."],"exampleFix":"// before\n// WinPEFile empty -> local_pe_not_specified\n// after\nsession.Config.WinPEFile = \"C:\\\\tools\\\\payload.exe\"  // then run with plugin winlogon","handlingStrategy":"validation","validationCode":"// Ensure WinPEFile is configured before the winlogon plugin runs\nif session.Config.WinPEFile == \"\" {\n    return errors.New(\"winlogon requires session.Config.WinPEFile to be set\")\n}","typeGuard":null,"tryCatchPattern":"result := plugin.Scan(ctx, host, session)\nif result != nil && !result.Success && result.Error.Error() == i18n.GetText(\"local_pe_not_specified\") {\n    // prompt/abort: the local PE path option is mandatory for winlogon\n}","preventionTips":["Always supply the PE path flag when the winlogon plugin is enabled.","Run a required-config preflight across all enabled plugins before scanning.","Update config templates after tool version upgrades where keys may be renamed."],"tags":["configuration","windows","winlogon","registry","missing-argument"],"backgroundTag":"missing-required-config-field","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}