Skip to content

fix: turn off the .NET startup hooks an environment variable can name - #3228

Merged
laurentiu021 merged 1 commit into
mainfrom
fix/no-startup-hooks
Nov 9, 2026
Merged

laurentiu021 merged 1 commit into
mainfrom
fix/no-startup-hooks

Conversation

@laurentiu021

Copy link
Copy Markdown
Owner

The .NET runtime loads every assembly a DOTNET_STARTUP_HOOKS variable names and runs its StartupHook.Initialize before Main. Any program running as you can set that variable for the programs you start later, also one you start as administrator, so an elevated SysManager would run code another program chose. SysManager uses no startup hook, so StartupHookSupport is now off and the runtime ignores the variable.

What changes

  • SysManager.csproj sets StartupHookSupport to false, in every configuration, so a test run in Debug reads the same runtime configuration the release ships. The SDK writes it as System.StartupHookProvider.IsSupported: false, and the runtime stops before it looks at the hooks the variable names.
  • SECURITY.md lists running a startup hook under "By design — forbidden", and a new "Things to be aware of" entry says what the runtime still reads from the environment: a profiler named in CORECLR_ or DOTNET_ variables, which nothing inside an app can turn off, since the runtime loads it before the app's code runs. The runtime reads those settings only from the environment, not from the runtime configuration.
  • The release's smoke check starts the published exe with DOTNET_STARTUP_HOOKS naming a hook that does not exist, set for that launch only, since pwsh is a .NET program too. An exe with hooks on refuses to start past a hook it cannot load, so a build that turned them back on fails the gate before anything is published.

How it was checked

  • A WPF exe published the way the release is (single file, self-contained, native libraries inside, compressed) ran a real startup hook named in the variable, and failed to start with exit code -532462766 when the hook did not exist. The same exe with StartupHookSupport off ignored both and started normally. The smoke check's lines, run through Start-Process against both, gave the same two outcomes, and left the variable unset afterwards.
  • SysManager published with the release's arguments carries "System.StartupHookProvider.IsSupported": false in the runtime configuration inside the exe.
  • SecurityPromiseTests.TheRuntime_RunsNoStartupHook failed on main's project, which sets nothing, and with the property set to true, and passes with it false.
  • Unit suite twice, the format check, and all four projects built with no warnings.

The .NET runtime loads every assembly a DOTNET_STARTUP_HOOKS variable
names and runs it before Main, and any program running as the user can
set that variable for the programs the user starts later, also one
started as administrator. A single-file exe published the way the
release is ran such a hook, and with StartupHookSupport off it ignored
the variable. SysManager uses no startup hook, so they are off now.

SECURITY.md lists running a startup hook among the things the app never
does, and says what the runtime still reads from the environment: a
profiler named in CORECLR_ or DOTNET_ variables, which nothing inside an
app can turn off, since the runtime loads it before the app's code runs.

SecurityPromiseTests.TheRuntime_RunsNoStartupHook reads the runtime
configuration the build wrote, which the single-file bundle carries, and
fails when it leaves startup hooks on. The release's smoke check starts
the published exe with a hook named that does not exist, which an exe
with hooks on refuses to start past.
@laurentiu021
laurentiu021 merged commit 335caed into main Nov 9, 2026
7 checks passed
@laurentiu021
laurentiu021 deleted the fix/no-startup-hooks branch November 9, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant