feat(onboarding-diag): allowlist ACG's own stack; downgrade Defender-off w/ 3rd-party AV (3d886f1a)

The probe flagged ACG's own MSP tooling (ScreenConnect/ConnectWise Control,
Splashtop, Syncro, Datto RMM, Datto EDR/AV) as CRITICAL "foreign agent" and
flagged Defender-off as CRITICAL even when a 3rd-party AV had legitimately
disabled it. Now: allowlisted tools emit an INFO "expected ACG tooling"
finding (genuinely-foreign tools still CRITICAL); Defender-off is downgraded
to INFO only when a 3rd-party AV is active. JSON contract + grading unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-31 16:22:38 -07:00
parent 63e46eacdf
commit 85509a71dc

View File

@@ -316,14 +316,52 @@ Invoke-Check -Id 'sec.foreign_agents' -Category 'security' -Title 'Competitor /
try { $svcRows = Get-Service -ErrorAction SilentlyContinue | Select-Object Name, DisplayName } catch { $svcRows = @() }
}
# ACG's OWN management / remote-access / security stack. A match here is
# EXPECTED tooling (we deploy it), so it is reported as INFO instead of the
# CRITICAL "foreign agent" finding. Detection of genuinely-foreign agents is
# NOT weakened: anything that matches a $patterns rule but is NOT on this
# allowlist is still flagged CRITICAL exactly as before.
#
# Matching is the same signal the foreign-agent scan uses (installed program
# DisplayName, service Name/DisplayName) plus the program Publisher, all
# case-insensitive (-match is case-insensitive in PS). Keep the aliases
# broad so common product/service-name variants are covered. To add a tool
# later, append another regex string to this array.
$acgOwnStack = @(
# ConnectWise Control / ScreenConnect (our remote-access tool)
'screenconnect|connectwise *control|connectwisecontrol',
# Splashtop (our remote-access tool)
'\bsplashtop\b',
# Syncro (our RMM/PSA) - SyncroMSP, kabuto, RepairTech lineage
'\bsyncro\b|syncromsp|\bkabuto\b|repairtech',
# Datto RMM (our RMM) - CagService, AEMAgent, CentraStage lineage
'datto *rmm|\bcagservice\b|\baemagent\b|centrastage',
# Datto EDR / Datto AV (our endpoint protection) - incl. Infocyte lineage
'datto *edr|datto *av|datto *antivirus|\bhuntress\b|infocyte|\brts\b'
)
# Returns the matching allowlist regex (truthy) if any allowlist entry
# matches the supplied text, else $null. Never throws.
function Test-AcgOwnStack {
param([string]$Text)
if ([string]::IsNullOrEmpty($Text)) { return $null }
foreach ($rx in $acgOwnStack) {
try { if ($Text -match $rx) { return $rx } } catch { }
}
return $null
}
$hits = @()
foreach ($pat in $patterns) {
$rx = $pat.rx
$matchEvidence = @()
$isOurs = $false # true if ANY matching signal for this label is ACG's own stack
foreach ($prog in $installed) {
if ($prog.Name -match $rx) {
$matchEvidence += ("program: " + $prog.Name + " " + $prog.Version)
# An install can be identified as ours by its DisplayName OR publisher.
if ((Test-AcgOwnStack $prog.Name) -or (Test-AcgOwnStack $prog.Publisher)) { $isOurs = $true }
}
}
foreach ($s in $svcRows) {
@@ -333,18 +371,27 @@ Invoke-Check -Id 'sec.foreign_agents' -Category 'security' -Title 'Competitor /
$st = ''
try { $st = [string]$s.State } catch { }
$matchEvidence += ("service: " + $sn + " (" + $sd + ") " + $st)
if ((Test-AcgOwnStack $sn) -or (Test-AcgOwnStack $sd)) { $isOurs = $true }
}
}
if ($matchEvidence.Count -gt 0) {
$hits += [pscustomobject]@{ Label = $pat.label; Evidence = ($matchEvidence | Select-Object -Unique) }
$hits += [pscustomobject]@{
Label = $pat.label
Evidence = ($matchEvidence | Select-Object -Unique)
IsOurs = $isOurs
}
}
}
Set-Fact 'foreign_agents' ($hits | ForEach-Object { $_.Label })
Set-Fact 'foreign_agents' ($hits | Where-Object { -not $_.IsOurs } | ForEach-Object { $_.Label })
Set-Fact 'acg_managed_tools' ($hits | Where-Object { $_.IsOurs } | ForEach-Object { $_.Label })
if ($hits.Count -gt 0) {
foreach ($h in $hits) {
$foreignHits = @($hits | Where-Object { -not $_.IsOurs })
$ourHits = @($hits | Where-Object { $_.IsOurs })
if ($foreignHits.Count -gt 0) {
foreach ($h in $foreignHits) {
Add-Finding -Id ('sec.foreign_agents.' + ($h.Label -replace '[^A-Za-z0-9]+','_').ToLower()) `
-Category 'security' -Severity 'critical' `
-Title ('Foreign management/remote-access agent: ' + $h.Label) `
@@ -357,6 +404,16 @@ Invoke-Check -Id 'sec.foreign_agents' -Category 'security' -Title 'Competitor /
-Detail 'No known competitor RMM or unmanaged remote-access agents found in installed programs or services.' `
-Evidence 'Scanned uninstall hives (HKLM + WOW6432Node) and Win32_Service'
}
# ACG's own stack is expected tooling. Report as INFO so it is visible in the
# inventory without being treated as a control/security risk.
foreach ($h in $ourHits) {
Add-Finding -Id ('sec.foreign_agents.acg.' + ($h.Label -replace '[^A-Za-z0-9]+','_').ToLower()) `
-Category 'security' -Severity 'info' `
-Title ('Expected ACG management tooling present: ' + $h.Label) `
-Detail 'This is Arizona Computer Guru managed/remote-access tooling that we deploy. Its presence is expected and not a foreign-agent risk.' `
-Evidence ($h.Evidence -join "`n")
}
}
# --- Firewall profiles ---