shadow1ng/fscan · error

local_pe_not_found

Error message

local_pe_not_found

What it means

WinStartupPlugin.Scan stats the configured PE path to confirm the local file exists before scanning Startup folders and Run keys for references to it. When os.Stat fails, it returns this localized 'local PE not found' error with the path embedded. No startup locations are inspected afterwards.

Source

Thrown at plugins/local/winstartup.go:34

)

type WinStartupPlugin struct {
	plugins.BasePlugin
}

func NewWinStartupPlugin() *WinStartupPlugin {
	return &WinStartupPlugin{
		BasePlugin: plugins.NewBasePlugin("winstartup"),
	}
}

func (p *WinStartupPlugin) Scan(ctx context.Context, info *common.HostInfo, session *common.ScanSession) *plugins.Result {
	pePath := session.Config.WinPEFile
	if pePath == "" {
		return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.GetText("local_pe_not_specified"))}
	}
	if _, err := os.Stat(pePath); err != nil {
		return &plugins.Result{Success: false, Error: fmt.Errorf("%s", i18n.Tr("local_pe_not_found", pePath))}
	}

	absPath, _ := filepath.Abs(pePath)
	fileName := filepath.Base(absPath)

	locations := []struct {
		name string
		dir  string
	}{
		{i18n.GetText("winstartup_user_folder"), filepath.Join(os.Getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")},
		{i18n.GetText("winstartup_common_folder"), filepath.Join(os.Getenv("ProgramData"), "Microsoft", "Windows", "Start Menu", "Programs", "Startup")},
	}

	var output strings.Builder
	var successCount int

	for _, loc := range locations {
		target := filepath.Join(loc.dir, fileName)

View on GitHub (pinned to 95cc12e753)

Solutions

  1. Check the file exists (Test-Path / os.Stat) and fix the configured path.
  2. Prefer absolute paths so behavior is CWD-independent.
  3. Restore the sample or update Config.WinPEFile to a valid copy.
  4. Verify permissions on the containing directory.

Example fix

// before
session.Config.WinPEFile = "sample.exe" // wrong CWD
// after
pe, _ := filepath.Abs("sample.exe")
if _, err := os.Stat(pe); err == nil {
    session.Config.WinPEFile = pe
}
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat(cfg.WinPEFile); err != nil {
    return fmt.Errorf("startup sample %q unavailable: %w", cfg.WinPEFile, err)
}

Try / catch

res := plugin.Scan(ctx, host, session)
if !res.Success {
    log.Errorf("winstartup scan failed: %v", res.Error) // inspect for not-found
}

Prevention

When it happens

Trigger: Config.WinPEFile is set but unresolvable: the file does not exist, a relative path resolves against the wrong CWD, the sample was removed/quarantined, or the path is inaccessible.

Common situations: Typo in the sample path; moving the tool or running it from another directory breaks a relative path; AV deleted the sample; the drive/share hosting the sample is unavailable.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of shadow1ng/fscan@95cc12e753 (2026-09-06). Data as JSON: /api/errors/275c609787fddb80. Report an issue: GitHub.