Quarantine registry-value findings (HKLM, HKCU, ...)#28
Merged
Conversation
scanner/browser_scanner.py emits a fair number of findings whose 'path' is a registry value (browser hijack run-keys, native-messaging hosts, side-loaded extension registrations). The vault couldn't contain them — File.Exists is false for HKLM\... — so the value stayed in the live registry and the scan report ended with 'Quarantine skipped (path not on disk)'. QuarantineService now handles registry-value paths alongside files and directories: - IsRegistryPath detects the HKLM/HKCU/HKCR/HKU (and HKEY_* long form) prefixes before NormalizeFullPath gets a chance to mangle the string into a CWD-relative path. - QuarantineRegistryEntry parses the path, opens the parent key writable, and checks whether the last segment is a value name on that key. If so, GetValueKind + GetValue(DoNotExpandEnvironmentNames) capture the value verbatim. The export — hive, subkey, value name, kind, payload — is written as <leaf>.reg.json into the vault, then DeleteValue removes it from the live registry. - Restore reads the JSON export, opens (or creates) the subkey, and SetValue restores the captured kind + payload. The JSON export file is deleted after a successful restore. - DeleteFromVault works unchanged — the export is just another file. - QuarantineRecord gains an IsRegistry flag (mutually exclusive with IsDirectory). Old records on disk default to false and continue to behave as files. - AutomatedResponseService gate now also accepts QuarantineService.IsRegistryPath() inputs. Value-level containment is enough for every shape browser_scanner actually emits today. Whole-key (subtree) quarantine surfaces a NotSupportedException with a clear message if a path resolves to a subkey rather than a value — left as a follow-up because it requires recursive export and ACL handling.
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.
Summary
Follow-up to #27 (directory-shaped quarantine).
scanner/browser_scanner.pyemits a fair number of findings whosepathis a registry value — browser-hijack run-keys, native-messaging hosts, side-loaded extension registrations. The vault couldn't contain them:File.Existsis false forHKLM\…, so the value stayed in the live registry and the scan report ended withQuarantine skipped (path not on disk).What changed
QuarantineService.csIsRegistryPath(string?)matchesHKLM,HKCU,HKCR,HKU(and the long-formHKEY_*variants) on the first segment.QuarantineFilechecksIsRegistryPathbeforeNormalizeFullPath— otherwisePath.GetFullPathwould mangle the string into a CWD-relative file path.QuarantineRegistryEntryparses the path, opens the parent key writable, and looks for a value with the matching last-segment name. If found,GetValueKind+GetValue(DoNotExpandEnvironmentNames)capture the value verbatim — important forREG_EXPAND_SZentries that legitimately use%SystemRoot%etc. (withoutDoNotExpandEnvironmentNames, the restore would write a fully-expanded path that breaks on a different machine state).<leaf>.reg.jsoninto the vault.DeleteValueruns only after the export is durable, so a crash mid-quarantine leaves the live registry intact.Restorefor anIsRegistryrecord reads the JSON, opens (or creates) the subkey, and writes the captured kind + payload back viaSetValue. The export file is deleted on success.DeleteFromVaultis unchanged — the export is just another file in the vault directory.QuarantineRecordgains anIsRegistryflag, mutually exclusive withIsDirectory. Old records on disk default both to false and continue to behave as files.AutomatedResponseService.cs— the existence gate now accepts registry paths alongside files and directories:Scope choice
Value-level containment covers every shape
browser_scanner.pyactually emits today. Whole-key (subtree) quarantine would need recursive export + ACL preservation — a separate feature. If a path resolves to a subkey rather than a value,QuarantineRegistryEntrythrowsNotSupportedExceptionwith"Registry KEY quarantine is not yet implemented"instead of silently failing, so the operator sees an actionable error.Test plan
HKCU\Software\Microsoft\Windows\CurrentVersion\Run, e.g.WraithTest→C:\does-not-exist.exe) and rescan. Expect the value to disappear fromregeditand aWraithTest.reg.jsonentry to appear in the vault.regeditwith the original kind (REG_SZ) and data.REG_EXPAND_SZvalue using%SystemRoot%\notepad.exe. Restore must preserve%SystemRoot%literally rather than expanding to the absolute path.NotSupportedException: Registry KEY quarantine is not yet implementedinstead of a silent skip.HKLMpath under an unelevated build (manually disable the manifest). Expect a clearUnauthorizedAccessExceptionrather than a corrupted half-quarantine.https://claude.ai/code/session_01LJscMnf6U5HycjwB89m1zU
Generated by Claude Code