Repository navigation
feat(machine-health): add browser-extension, network-listener and firewall-rule checks - #8940
Conversation
Adds the browser-extensions check (catalog 23, security): every Chrome, Edge and Firefox extension per profile as a mutable FindingItem, and the Edge and Chrome forcelist and ExtensionSettings policies read in both hives. Unpacked, command-line, sideloaded, unsigned or foreign-installed extensions and high-attention permissions are WARN; an unreadable source is UNKNOWN. Location-less Chromium stubs are dropped and counted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the network-listeners check (catalog 24, security): each listening program, protocol and port as a mutable FindingItem, resolved through the process path, then the hosting service, else left unresolved. Exposed listeners whose binary is unsigned or user-writable are WARN; unresolved listeners carry no key and read UNKNOWN, never OK. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the firewall-rules check (catalog 25, security, INFO always): inbound allow rules whose Name is not in the SystemDefaults store, read in bulk and joined on InstanceID, with per-version rules grouped so an update keeps the mute. program_state separates a missing program from one under a folder the caller cannot traverse. A per-version rule the unelevated port-filter read missed gets a capped per-rule read; one still unread is listed without a key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A second fleet host holds the same SystemDefaults rule names, and neither host's candidates intersect the other's SystemDefaults names, so firewall-rules now reports baseline_hosts = 2 and section 25 records the confirmation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New-FindingItem gains -NoKey/-NoKeyReason for an item whose identity could not be read: key null, never muted, the reason recorded. Every title passes through the new Format-MachineText, which caps machine text and replaces control, escape and bidi-override characters; checks use it for their machine-derived fields. output-schema.md says when key is null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An unreadable browser, profile file or policy key now makes the check UNKNOWN even when items are listed. Each profile reads inside its own guard, with a size cap, an object-root check and TryParse for location. Chromium claims are cross-checked: an absolute install path, a policy location no policy names, and a component outside the browser install are flagged. Off-store forcelist entries are listed-off-store unless the extension is installed. Items name the profile folder, update URLs lose their query string, and machine text is sanitized. Both adapters build records through New-ExtensionRecord. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….sys queues Listener owners now resolve from the kernel-reported image path (QueryFullProcessImageNameW), with Get-Process's path kept as a process-reported fallback. Kernel TCP ports served by http.sys are traced to their request queue owner through netsh; an owner that cannot be found, or unreadable netsh output, leaves the port unresolved. An unread socket table or service list now makes the check UNKNOWN even with items listed, unresolved listeners are built as unkeyed FindingItems, and machine text is sanitized. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…unts firewall-rules never probes a UNC path or a network-drive program (it reports them unknown), runs its program probes under the adapter's time budget, keeps rule names out of the summary, builds unkeyed items through New-FindingItem, sanitizes machine text, and has one catch instead of two. Catalog section 25 keeps the rubric and points to the adapter for the mechanics; the listener check's bind-rank comment now points to section 24. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e names Section 25's baseline and missing-program records named capture files and a plan that live outside the public repository. Both now state the decision and what was observed on the fleet hosts, with the as-of date and recheck trigger. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and tighten sources One malformed profile no longer fails browser-extensions: it reads UNKNOWN, keeps the other profiles' items, leaves ran_successfully true, and names the unread sources in detail.unreadable_sources. Chromium pointers now carry commit and line anchors; section 24 documents the fixed `system` identity for kernel-owned listeners; Format-MachineText also replaces U+2028 and U+2029; test headers cite the catalog or describe their redacted fixture shapes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
claude-security-review reviewed Security review (incremental, 54241f9..b5dece2): no security findings. I read
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54241f9f50
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
claude-review reviewed Incremental review (54241f9..b5dece2): no findingsRead the incremental diff against the PR context and the surrounding code. Network was blocked, so I could not open the new Mozilla source links or the replacement
I ran no tests myself. The PR's pass counts are author-claimed and unverified. |
…icy_entries detail.policy_entries now carries every installing ExtensionSettings id beside the forcelist rows, labeled by source, with its hive, update URL without the query string, and install mode, so an off-store entry that raises blocked_marker_count is identifiable. Machine text in each entry is sanitized. Catalog section 23 pins the Mozilla signedState and install-location sources and says the kind mapping is our judgment; the netsh pointer in section 24 follows Learn's redirect to a live anchor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No related issue: Phase 7 of the owner-approved machine-health PC-checkup plan (ADR 0081, #8906).
Summary
The owner asked to "look for anything that shouldn't be here". This PR adds three intruder inventories, each as mutable FindingItems:
There is one commit per check, followed by the review and verifier rounds.
Fix
Browser extensions
Get-ChromiumExtensionmerges Preferences with Secure Preferences, and drops and counts the stub entries that have no location. Each profile is read inside its own try. Files have a size cap, and a profile name that is not a single folder name is refused.Get-FirefoxExtensionhandles Firefox.Get-ExtensionPolicyreads both forcelist keys for Edge and Chrome, in both hives, labeled by hive.New-ExtensionRecordis the one record constructor.policywith no matching policy entry, orcomponentoutside the browser install folder.listed-off-store.unreadable_sources, but the check still keeps the other profiles' items.Network listeners
Get-ListenerOwnerresolves each process image with the kernel-suppliedQueryFullProcessImageNameW, falling back toGet-Process.netsh http show servicestate view=requestq.Firewall rules
Get-FirewallRuleInventorymakes bulk reads of rules, SystemDefaults names, application filters (exactly one call) and port filters.baseline_hosts = 2after the second-host check.Shared
New-FindingItem -NoKeybuilds unkeyed items.Format-MachineTextcaps machine strings at 300 characters and strips C0, C1, ESC, bidi and U+2028/2029 characters.Catalog and changelog
security, and sections 23 to 25, with pointers anchored to the Learn sections and pinned Chromium source lines.minor).Verification
run-tests.ps1exits 0: 985 passed, 0 failed, 1 skipped. All 10 filtered suites exit 0.not-foundprogram failsGet-Itemwith item-not-found, never access-denied (7 of 7).browser-extensions1418 ms,network-listeners14573 ms,firewall-rules3766 ms.Related
The sibling top-processes and backup PR adds the generic appendix arm that renders these items in the markdown report.
🤖 Generated with Claude Code