fix: say so when App Blocker cannot lift a block, instead of leaving it in the list - #2358
Merged
Merged
Conversation
…it in the list (#2357) #2030 stopped the app CREATING an IFEO block on consent.exe. It did nothing for a machine an older build had already written one on, and that is the case that strands somebody: unblocking writes to HKLM, which needs elevation, which needs the consent UI the block disabled. Such an entry sat in the blocked list as an ordinary row beside the deliberate ones, next to an Unblock button that could never succeed, with nothing saying why. Detection only. Nothing is removed automatically, elevated or not — the repair stays the existing Unblock button behind its confirmation dialog. - Extract the refusal predicate so one definition serves both refusing a new block and recognising an old one, instead of two lists that could drift about which entries matter. - GetBlockedApps stamps the verdict onto each row, so the flag travels with the data and cannot be derived a second, differing way by whoever displays it. - Mark the row, and show a banner naming what was lost. The recovery step branches on elevation: the button when the app can use it, the exact registry value and location when no permission prompt can appear to grant it. - Raise it on the Dashboard as a red alert routed to the tab, because the damage is invisible until the first elevation request. - Say what a block looks like in the confirmation: Windows reports it cannot find SysManager_Blocked.exe. That absent file IS the mechanism, and it stays that way — a real stub in System32 is a worse trade for an unsigned app, and a stub on a writable path invoked by an elevated target would be a privilege problem. An empty IFEO key and a third-party Debugger are both excluded, so a partially repaired machine raises no permanent unfixable warning about nothing. Regression test red before the fix, green after: with the classification forced to false, 4 of the 19 new service tests fail reporting IsUnrecoverable = False, and the other 15 stay green because they do not depend on it. The UI binding test was proved the same way — mistyping the bound property name fails it. Tests: 5845 unit (+30), 3 new integration. Whole unit suite green locally, 0 failed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2357
The gap
#2030 stopped the app creating an IFEO block on
consent.exe. It did nothing about a machine where anolder build already wrote one — and that is the case that strands someone, because the undo is circular:
UnblockAppwrites to HKLM, which needs elevation, which forconsent.exeneeds the process the blockdisabled.
So an affected machine listed
consent.exein App Blocker as an ordinary row beside the deliberate blocks,with an Unblock button that could never succeed, and nothing anywhere saying why or what to do instead. The
machine looks healthy right up to the first time something asks for administrator rights.
Verified against the tags rather than from memory:
v1.65.13(2026-08-17) did not carryconsent.exeinBootCriticalExecutables; the guard arrived in7dc0c607two weeks later.What this does
Detection only. Nothing is removed automatically, elevated or not. The repair stays the existing Unblock
button behind the confirmation dialog it already uses — an unattended registry write is the user's decision,
not the app's.
one read the same definition. Two copies is precisely how they would come to disagree about which entries
are dangerous, and getting that wrong fails open: an unmatched name reads as "no problem".
GetBlockedAppsstamps it onto each row, so nothing downstream canderive it a second, differing way.
on elevation — the button when the app can actually use it, the exact registry value and location when no
permission prompt can appear to grant it. A single static sentence would have been wrong in one of those
two states, and the state it would be wrong in is the stranded one.
invisible until the first elevation request, which makes the App Blocker tab the last place anyone would
think to look.
launch. What you see is a Windows error saying it cannot find
SysManager_Blocked.exe, which reads asSysManager having broken the computer.
What is deliberately NOT here
A stub in System32. The absent file is the mechanism — a
Debuggerpath that does not resolve is whythe launch fails. Requiring it to exist before writing would refuse every block and kill the feature.
Shipping a real one is a worse trade for an unsigned app, and a stub on a user-writable path invoked by an
elevated target would be a genuine privilege problem.
regedit.exe/cmd.exe/powershell.exeadded to the refusal list. The list's own criterion is"blocking it removes the means of unblocking it", and these do not meet it — the app is the undo path and it
keeps working. Blocking a shell for a household member is also a legitimate use of this tab, and refusing it
would remove a real capability to guard against a recoverable state.
Automatic removal when elevated. It was in the first draft and was dropped: it is a silent registry write
nobody asked for.
Proof
Regression test red before the fix, green after. With the classification forced to
false, 4 of the 19new service tests fail — each reporting
IsUnrecoverable = False— and the other 15 stay green, because theydo not depend on that line. Full output was read, not just the summary.
The damage is reproduced the way it actually happened: the value written straight into a redirected hive,
bypassing
TryBlockApp, because today's code refuses to write it. A test going through the service could notset this state up at all — which is exactly why the gap survived, since the only supported path already
refuses and nothing exercised the unsupported one.
The UI test was proved the same way. Mistyping the bound property name in the XAML fails
TheBanner_ShowsTheViewModelsWords_WhenStranded; restoring it passes. It reads the renderedTextBlockrather than the view model, so a correctly computed property bound to nothing cannot pass.
Negative cases, which matter as much here. An empty IFEO key and a third-party
Debuggerare bothexcluded, so a partially repaired machine raises no permanent unfixable warning about nothing — that key
cannot be removed without administrator rights, so such a warning would never clear.
Dashboard alert tested through a pure classifier, matching every other alert on that page: the scan's only
other statement is a
Dispatcher.BeginInvoke, and with noApplication.Currentthat call short-circuits, soa test driving the scan would assert against an untouched alert and pass while proving nothing.
dotnet format --verify-no-changesArchitectureTests(blocking guards)Docs updated in this PR: README App Blocker section, ARCHITECTURE service entry, CHANGELOG.
SECURITY.mdalready reads
1.111.x, which covers this patch.