Skip to content

Fix Mark of the Web detection by removing MUTZ_ISFILE flag#54937

Open
Evangelink wants to merge 2 commits into
mainfrom
evangelink-fix-mark-of-the-web-test
Open

Fix Mark of the Web detection by removing MUTZ_ISFILE flag#54937
Evangelink wants to merge 2 commits into
mainfrom
evangelink-fix-mark-of-the-web-test

Conversation

@Evangelink

@Evangelink Evangelink commented Jun 23, 2026

Copy link
Copy Markdown
Member

Problem

DangerousFileDetectorTests.ItShouldDetectFileWithMarkOfTheWeb was failing on CI:

Expected boolean to be True, but found False.

The test writes a Zone.Identifier stream (ZoneId=3, Mark of the Web) and expects the file to be reported as dangerous.

Root cause

The interop modernization made two changes to DangerousFileDetector that broke Mark-of-the-Web detection:

  1. MapUrlToZone flags changed from 0 to MUTZ_ISFILE. MUTZ_ISFILE maps the zone from the file location only and ignores the Zone.Identifier stream.

  2. COM activation changed from Activator.CreateInstance to CoGetClassObject + IClassFactory::CreateInstance. InternetSecurityManager is registered with the apartment threading model. The CLR's Activator.CreateInstance path (effectively CoCreateInstance) honors that model: when called from an MTA thread — the xUnit runner's default — COM hosts the object in an STA and returns a marshaled proxy. Creating the object directly through its class factory places it in the calling MTA apartment, where MapUrlToZone cannot read the Zone.Identifier stream and returns LocalMachine. This is why the test failed only on CI agents while passing on some dev machines.

Fix

  • Restore the MapUrlToZone flags argument to 0 so the Zone.Identifier stream is read.
  • Activate InternetSecurityManager via CoCreateInstance (already present in NativeMethods.txt) instead of the class factory, so COM honors the registered ThreadingModel and apartment-hosts the object as the original code did.

ComClassFactory is retained — it's still used for the VS SetupConfiguration object (which is ThreadingModel=Both and therefore unaffected).

Verification

  • Microsoft.DotNet.Cli.Utils builds clean (0 warnings/errors).
  • A standalone repro running the fixed assembly on an explicit MTA thread (matching the test runner) now returns True for a file with Mark of the Web (ZoneId=3) and False for a clean file.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

The interop modernization changed the MapUrlToZone flags argument from 0 to MUTZ_ISFILE. MUTZ_ISFILE maps the zone based solely on the file location and ignores the Zone.Identifier alternate data stream (Mark of the Web), so downloaded files were no longer detected as dangerous. Restoring the flag to 0 makes MapUrlToZone read the Zone.Identifier stream again.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 23, 2026 07:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes Mark of the Web (Zone.Identifier ADS) detection in DangerousFileDetector by ensuring IInternetSecurityManager.MapUrlToZone is invoked with flags 0, allowing the zone to be derived from the file’s Mark of the Web metadata rather than solely from its location.

Changes:

  • Change MapUrlToZone call to pass dwFlags = 0 instead of PInvoke.MUTZ_ISFILE.
  • Add an explanatory comment documenting why MUTZ_ISFILE must not be used for this scenario.
Show a summary per file
File Description
src/Cli/Microsoft.DotNet.Cli.Utils/DangerousFileDetector.cs Restores MapUrlToZone(..., 0) so Mark of the Web is respected; adds rationale comment to prevent regression.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

@Evangelink Evangelink enabled auto-merge June 23, 2026 08:10
…ent model

Removing MUTZ_ISFILE alone was not enough: the modernization also replaced Activator.CreateInstance (CLR COM activation, equivalent to CoCreateInstance) with CoGetClassObject + IClassFactory::CreateInstance. The latter creates the apartment-model InternetSecurityManager directly in the calling MTA apartment (the xUnit runner's default) instead of letting COM host it in an STA and return a marshaled proxy. In the wrong apartment MapUrlToZone cannot read the Zone.Identifier (Mark of the Web) stream and reports LocalMachine, so the test failed only on CI agents. Switch to CoCreateInstance, which honors the registered ThreadingModel and restores the original behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

3 participants