SonicWall SSLVPN SAML Bypass: Hunt Alternate Logins


What this means for your clients: a work-network login may succeed without the extra approval your business expects.
A successful VPN session does not establish that someone passed your MFA policy. The SonicWall SSLVPN SAML bypass makes that distinction urgent: valid alternate credentials may avoid the identity provider that normally challenges them. Ask whether the accepted session actually passed through it.
The password can work without the expected approval
SonicWall's CNA record describes CVE-2026-19868 as an authentication-enforcement vulnerability in SonicOS SSLVPN. Someone must already possess valid credentials for an alternate authentication method; exploitation may bypass SAML controls and SAML-enforced MFA. This is not evidence that anybody can connect without credentials. Nor does the record name the alternate authentication methods it covers.
SAML puts the identity provider in charge of proving identity and applying approval policy. The firewall still grants network access. An identity-provider policy cannot protect a request that never reached it. Investigate both records together.
CISA added the vulnerability to KEV on November 6. Its November 20 deadline applies to covered federal agencies, not a universal grace period. Victims, exploitation volume and ransomware involvement are not established by the available sources.
Establish the affected build before changing the appliance
The vendor-authored CNA lists 7.3.3-7015 and older, and 8.2.2-8015 and older, as affected on Gen7 and Gen8. BleepingComputer reports fixes in 7.3.4-7013 and 8.2.3-8015, no workaround, and impact on SSLVPN configured for SAML. The fixes and workaround claim are secondary-sourced; SonicWall's PSIRT page was unavailable during verification.
Canada's advisory instead says Gen8 versions before 8.2.2-8015. SonicWall's CNA record includes that build as affected; do not clear it using Canada's boundary. Do not clear an intermediate build absent vendor confirmation. Inventory exposed SSLVPN services and confirm each supported upgrade with SonicWall. Prioritize affected systems. Do not treat removing an unspecified alternate method as a verified vendor workaround.
Preserve appliance configuration, SSLVPN authentication syslog, session records and relevant identity-provider logs before upgrades or log rotation. Record the build and whether SAML was enabled at the time of each connection. Preserve tunnel assignments and firewall flows for endpoint correlation. Investigate unexpected sessions, revoke confirmed unauthorized access and replace implicated credentials through the response process. Patching does not explain sessions already accepted.
Test raw completeness before hunting absence
These unexecuted templates use a closed normalized schema, not stock connectors. Start with the mapping appendix's Start here steps; the optional reference packet illustrates them. No vendor parser or native execution has been validated.
Audit raw receipts before classification, retaining exclusions and unrecognized records. Compare independent totals, not surviving timestamps. Require VPN and IdP coverage for Hunt 2, and VPN and endpoint telemetry for Hunt 4, separately for each tenant. Unknown identity, conflicting session starts or undeclared fields reject the reference batch, including out-of-window conflicts. Local preflight checks never approve a negative result.
All analytical times are original-event UTC milliseconds. Evidence spans 30 days ending November 7 at 10:30 AM MST, exclusive. Hunts start November 1 at midnight MST, an analyst floor, not an exploitation start. Use dedicated, unmixed datasets. For Sentinel, the appendix specifies a DCR design that is untested and not deployed. It would use Microsoft's documented transform to set TimeGenerated to data import time, keeping historical event_ms as a long. Set the Sentinel query time range to the data import-time interval; event_ms selects the historical hunt range. CQL's bounded historical joins still require native time to mirror original time.
Before interpretation, independently reconcile complete staged payloads, source inventories, exclusions, lookups and relevant gap counts, then validate the target engine and job limits. Receipt-time selection is not source retention. Missing rows, unknown decision evidence, partial jobs or truncated exports mean inconclusive, not clean. The appendix gives exact schema, clock and partition rules.
Splunk
index=sonicwall_coverage earliest=0 latest=now
| where scope_id="sonicwall-20261107-v6"
| stats sum(raw_records) AS raw_records sum(raw_expected_records) AS raw_expected_records sum(targeted_messages) AS targeted_messages sum(excluded_records) AS excluded_records sum(unrecognized_records) AS unrecognized_records sum(normalized_matches) AS normalized_matches sum(timestamp_gaps) AS timestamp_gaps sum(mapping_gaps) AS mapping_gaps sum(manifest_gaps) AS manifest_gaps sum(binding_not_applicable) AS binding_not_applicable sum(h1_gap) AS h1_gap sum(h2_gap) AS h2_gap sum(h3_gap) AS h3_gap sum(h4_gap) AS h4_gap BY snapshot_id coverage_sourceElastic
FROM sonicwall-coverage
| WHERE scope_id=="sonicwall-20261107-v6"
| STATS raw_records=SUM(raw_records),raw_expected_records=SUM(raw_expected_records),targeted_messages=SUM(targeted_messages),excluded_records=SUM(excluded_records),unrecognized_records=SUM(unrecognized_records),normalized_matches=SUM(normalized_matches),timestamp_gaps=SUM(timestamp_gaps),mapping_gaps=SUM(mapping_gaps),manifest_gaps=SUM(manifest_gaps),binding_not_applicable=SUM(binding_not_applicable),h1_gap=SUM(h1_gap),h2_gap=SUM(h2_gap),h3_gap=SUM(h3_gap),h4_gap=SUM(h4_gap) BY snapshot_id,coverage_source
| LIMIT 10000CrowdStrike
dataset="sonicwall_coverage"
| scope_id="sonicwall-20261107-v6"
| groupBy([snapshot_id,coverage_source],function=[sum(raw_records,as=raw_records),sum(raw_expected_records,as=raw_expected_records),sum(targeted_messages,as=targeted_messages),sum(excluded_records,as=excluded_records),sum(unrecognized_records,as=unrecognized_records),sum(normalized_matches,as=normalized_matches),sum(timestamp_gaps,as=timestamp_gaps),sum(mapping_gaps,as=mapping_gaps),sum(manifest_gaps,as=manifest_gaps),sum(binding_not_applicable,as=binding_not_applicable),sum(h1_gap,as=h1_gap),sum(h2_gap,as=h2_gap),sum(h3_gap,as=h3_gap),sum(h4_gap,as=h4_gap)],limit=max)Microsoft KQL
SonicWallCoverage_CL
| where scope_id=="sonicwall-20261107-v6"
| summarize raw_records=sum(raw_records),raw_expected_records=sum(raw_expected_records),targeted_messages=sum(targeted_messages),excluded_records=sum(excluded_records),unrecognized_records=sum(unrecognized_records),normalized_matches=sum(normalized_matches),timestamp_gaps=sum(timestamp_gaps),mapping_gaps=sum(mapping_gaps),manifest_gaps=sum(manifest_gaps),binding_not_applicable=sum(binding_not_applicable),h1_gap=sum(h1_gap),h2_gap=sum(h2_gap),h3_gap=sum(h3_gap),h4_gap=sum(h4_gap) by snapshot_id,coverage_sourceCompare raw_records with raw_expected_records, classifications and normalized matches. Investigate gaps and missing sources. Zero gaps never replace independent read-back and engine checks. Generated h1_ready through h4_ready flags are per-record checks, not SonicWall fields or source-level approval. Unresolved evidence appears in notes.json, excluded from confirmed leads.
Hunt 1: Find the verified alternate path
Look for users expected to use SAML whose successful VPN session demonstrably used another method. Unknown authentication metadata must not become a bypass finding.
Splunk
index=sonicwall_hunt earliest=0 latest=now
| where event_ms >= 1793516400000 AND event_ms < 1794072600000
| search h1_ready="true" kind="vpn_success" saml_enabled="true" expected_saml="true" auth_path="alternate_verified"
| table event_ms tenant_id appliance_id record_id service_id principal_id session_key source_ip auth_pathElastic
FROM sonicwall-hunt
| WHERE event_ms >= 1793516400000 AND event_ms < 1794072600000
| WHERE h1_ready=="true"
| WHERE kind=="vpn_success" AND saml_enabled=="true" AND expected_saml=="true" AND auth_path=="alternate_verified"
| KEEP event_ms,tenant_id,appliance_id,record_id,service_id,principal_id,session_key,source_ip,auth_path
| LIMIT 10000CrowdStrike
dataset="sonicwall_hunt"
| h1_ready="true"
| event_ms >= 1793516400000
| event_ms < 1794072600000
| kind="vpn_success" saml_enabled="true" expected_saml="true" auth_path="alternate_verified"
| select([event_ms,tenant_id,appliance_id,record_id,service_id,principal_id,session_key,source_ip,auth_path])Microsoft KQL
SonicWallHunt_CL
| where event_ms >= 1793516400000 and event_ms < 1794072600000
| where h1_ready=="true"
| where kind=="vpn_success" and saml_enabled=="true" and expected_saml=="true" and auth_path=="alternate_verified"
| project event_ms,tenant_id,appliance_id,record_id,service_id,principal_id,session_key,source_ip,auth_pathHere auth_path="alternate_verified" is an analyst-defined classification backed by actual authentication evidence, not a SonicWall method name. saml_enabled and expected_saml require time-valid configuration and account-policy enrichment. Blank methods stay unknown. Planned exceptions can match; compare the original record and approved policy before escalation.
Hunt 2: Reconcile the session with its identity provider
A VPN success with no corresponding SAML success deserves investigation, but missing logs are not proof that MFA was bypassed.
Splunk
index=sonicwall_hunt earliest=0 latest=now
| where event_ms >= 1793516400000 AND event_ms < 1794072300000
| search h2_ready="true" kind="vpn_success" saml_enabled="true"
| where isnotnull(join_key) AND join_key!="" AND join_key!="-" AND isnotnull(session_key) AND session_key!="" AND session_key!="-"
| fields join_key tenant_id appliance_id record_id principal_id service_id session_key event_ms
| join type=left max=0 join_key [
index=sonicwall_hunt earliest=0 latest=now
| where event_ms >= 1793516100000 AND event_ms < 1794072600000
| search h2_ready="true" kind="idp_saml_success"
| fields join_key event_ms
| rename event_ms AS rhs_idp_ms
| fields join_key rhs_idp_ms
]
| eval idp_hit=if(isnotnull(rhs_idp_ms) AND rhs_idp_ms>=event_ms-300000 AND rhs_idp_ms<=event_ms+300000,1,0)
| stats max(idp_hit) AS idp_matches BY tenant_id appliance_id record_id principal_id service_id session_key event_ms
| where idp_matches=0Elastic
FROM sonicwall-hunt
| WHERE event_ms >= 1793516400000 AND event_ms < 1794072300000
| WHERE h2_ready=="true"
| WHERE kind=="vpn_success" AND saml_enabled=="true" AND join_key IS NOT NULL AND join_key!="" AND join_key!="-" AND session_key IS NOT NULL AND session_key!="" AND session_key!="-"
| KEEP join_key,tenant_id,appliance_id,record_id,principal_id,service_id,session_key,event_ms
| LOOKUP JOIN sonicwall-idp-lookup ON join_key
| EVAL idp_hit=CASE(rhs_idp_ms IS NOT NULL AND rhs_idp_ms>=event_ms-300000 AND rhs_idp_ms<=event_ms+300000,1,0)
| STATS idp_matches=MAX(idp_hit) BY tenant_id,appliance_id,record_id,principal_id,service_id,session_key,event_ms
| WHERE idp_matches==0
| LIMIT 10000CrowdStrike
dataset="sonicwall_hunt"
| h2_ready="true"
| event_ms >= 1793516400000
| event_ms < 1794072300000
| kind="vpn_success" saml_enabled="true" join_key=* join_key!="" join_key!="-" session_key=* session_key!="" session_key!="-"
| select([@timestamp,join_key,tenant_id,appliance_id,record_id,principal_id,service_id,session_key,event_ms])
| join(query={
dataset="sonicwall_hunt" h2_ready="true" kind="idp_saml_success"
| event_ms >= 1793516100000
| event_ms < 1794072600000
| select([@timestamp,join_key,event_ms])
| rhs_idp_ms:=event_ms
},field=join_key,include=[rhs_idp_ms],mode=left,max=200000,limit=200000,
start="1793516100000",end="1794072600000")
| case {
rhs_idp_ms=* rhs_idp_ms!=""
| delta_ms:=event_ms-rhs_idp_ms
| case { delta_ms>=-300000 delta_ms<=300000 | idp_hit:=1; * | idp_hit:=0; };
* | idp_hit:=0;
}
| groupBy([tenant_id,appliance_id,record_id,principal_id,service_id,session_key,event_ms],function=[max(idp_hit,as=idp_matches)],limit=max)
| idp_matches=0Microsoft KQL
let IdP = SonicWallHunt_CL
| where event_ms >= 1793516100000 and event_ms < 1794072600000
| where h2_ready=="true"
| where kind=="idp_saml_success"
| project join_key,rhs_idp_ms=event_ms;
SonicWallHunt_CL
| where event_ms >= 1793516400000 and event_ms < 1794072300000
| where h2_ready=="true"
| where kind=="vpn_success" and saml_enabled=="true"
| where isnotempty(join_key) and join_key!="-" and isnotempty(session_key) and session_key!="-"
| project join_key,tenant_id,appliance_id,record_id,principal_id,service_id,session_key,event_ms
| join kind=leftouter IdP on join_key
| summarize idp_matches=countif(isnotnull(rhs_idp_ms) and rhs_idp_ms>=event_ms-300000 and rhs_idp_ms<=event_ms+300000) by tenant_id,appliance_id,record_id,principal_id,service_id,session_key,event_ms
| where idp_matches==0Build join_key from tenant, canonical principal and the specific VPN SAML application. Do not collapse same-named accounts across domains. Elastic requires a complete lookup-mode sonicwall-idp-lookup containing that key and rhs_idp_ms; the other three platforms join normalized events directly. The five-minute allowance is a tuning assumption, not a documented exploit interval. Another legitimate IdP success can suppress a lead; a match does not prove assertion consumption or an MFA challenge. Check clocks, delayed logs and reusable assertions. The last five minutes are excluded to allow the matching tail. Truncated joins cannot support a missing-match conclusion.
Hunt 3: Find new identity and source pairs
Find new identity and source IP pairs on privileged accounts. Review every new pair, then use session counts to prioritize rather than discarding frequent successes.
Splunk
index=sonicwall_hunt earliest=0 latest=now
| where event_ms >= 1791480600000 AND event_ms < 1794072600000
| search h3_ready="true" kind="vpn_success"
| where isnotnull(principal_id) AND principal_id!="" AND principal_id!="-" AND isnotnull(source_ip) AND source_ip!="" AND source_ip!="-"
| eval prior=if(event_ms<1793516400000,1,0), recent_target=if(event_ms>=1793516400000 AND saml_enabled="true" AND privileged="true",1,0)
| stats max(prior) AS prior max(recent_target) AS recent_target max(event_ms) AS last_ms BY tenant_id appliance_id principal_id source_ip session_key
| stats sum(prior) AS baseline_sessions sum(recent_target) AS recent_sessions max(last_ms) AS last_all_vpn_ms BY tenant_id appliance_id principal_id source_ip
| where baseline_sessions=0 AND recent_sessions>0Elastic
FROM sonicwall-hunt
| WHERE event_ms >= 1791480600000 AND event_ms < 1794072600000
| WHERE h3_ready=="true"
| WHERE kind=="vpn_success" AND principal_id IS NOT NULL AND principal_id!="" AND principal_id!="-" AND source_ip IS NOT NULL AND source_ip!="" AND source_ip!="-"
| EVAL prior=CASE(event_ms<1793516400000,1,0), recent_target=CASE(event_ms>=1793516400000 AND saml_enabled=="true" AND privileged=="true",1,0)
| STATS prior=MAX(prior),recent_target=MAX(recent_target),last_ms=MAX(event_ms) BY tenant_id,appliance_id,principal_id,source_ip,session_key
| STATS baseline_sessions=SUM(prior),recent_sessions=SUM(recent_target),last_all_vpn_ms=MAX(last_ms) BY tenant_id,appliance_id,principal_id,source_ip
| WHERE baseline_sessions==0 AND recent_sessions>0
| LIMIT 10000CrowdStrike
dataset="sonicwall_hunt"
| h3_ready="true"
| event_ms >= 1791480600000
| event_ms < 1794072600000
| kind="vpn_success" principal_id=* principal_id!="" principal_id!="-" source_ip=* source_ip!="" source_ip!="-"
| case { event_ms<1793516400000 | prior:=1; * | prior:=0; }
| case { event_ms>=1793516400000 saml_enabled="true" privileged="true" | recent_target:=1; * | recent_target:=0; }
| groupBy([tenant_id,appliance_id,principal_id,source_ip,session_key],function=[max(prior,as=prior),max(recent_target,as=recent_target),max(event_ms,as=last_ms)],limit=max)
| groupBy([tenant_id,appliance_id,principal_id,source_ip],function=[sum(prior,as=baseline_sessions),sum(recent_target,as=recent_sessions),max(last_ms,as=last_all_vpn_ms)],limit=max)
| baseline_sessions=0 recent_sessions>0Microsoft KQL
SonicWallHunt_CL
| where event_ms >= 1791480600000 and event_ms < 1794072600000
| where h3_ready=="true"
| where kind=="vpn_success" and isnotempty(principal_id) and principal_id!="-" and isnotempty(source_ip) and source_ip!="-"
| extend prior=iff(event_ms<1793516400000,1,0),recent_target=iff(event_ms>=1793516400000 and saml_enabled=="true" and privileged=="true",1,0)
| summarize prior=max(prior),recent_target=max(recent_target),last_ms=max(event_ms) by tenant_id,appliance_id,principal_id,source_ip,session_key
| summarize baseline_sessions=sum(prior),recent_sessions=sum(recent_target),last_all_vpn_ms=max(last_ms) by tenant_id,appliance_id,principal_id,source_ip
| where baseline_sessions==0 and recent_sessions>0The baseline begins October 8 at 10:30 AM MST, about 23.56 days before November 1. It is historical observation, not a known-benign period. Earlier unauthorized access can contaminate it; incomplete retention invalidates novelty. The local checks require reviewed baseline coverage. Queries count distinct sessions after record deduplication, include every new pair and label the last timestamp across VPN successes. Privilege comes from account inventory, not username guesses. Travel, shared egress and appliance migration can produce benign matches.
Hunt 4: Follow the session onto a real endpoint
Follow Hunt 1 sessions into verified administrative logons or seven generic Windows process names within an hour. This does not follow Hunt 2-only leads or evaluate process-tree suspiciousness.
Splunk
index=sonicwall_hunt earliest=0 latest=now
| where event_ms >= 1793516400000 AND event_ms < 1794072600000
| eval process_name=lower(process_name)
| where h4_ready="true"
| where kind="endpoint_admin_logon" OR (kind="endpoint_process" AND in(process_name,"powershell.exe","pwsh.exe","cmd.exe","wmic.exe","winrs.exe","mstsc.exe","psexec.exe"))
| where isnotnull(session_key) AND session_key!="" AND session_key!="-"
| fields session_key event_ms tenant_id principal_id endpoint_id kind process_name parent_name command_line record_id
| join type=inner max=0 session_key [
index=sonicwall_hunt earliest=0 latest=now
| where event_ms >= 1793516400000 AND event_ms < 1794072600000
| search h4_ready="true" kind="vpn_success" saml_enabled="true" expected_saml="true" auth_path="alternate_verified"
| fields session_key event_ms principal_id
| rename event_ms AS rhs_vpn_ms principal_id AS rhs_vpn_principal
| fields session_key rhs_vpn_ms rhs_vpn_principal
]
| where event_ms>=rhs_vpn_ms AND event_ms<=rhs_vpn_ms+3600000
| table event_ms tenant_id session_key rhs_vpn_ms rhs_vpn_principal principal_id endpoint_id kind process_name parent_name command_line record_idElastic
FROM sonicwall-hunt
| WHERE event_ms >= 1793516400000 AND event_ms < 1794072600000
| EVAL process_name=TO_LOWER(process_name)
| WHERE h4_ready=="true"
| WHERE kind=="endpoint_admin_logon" OR (kind=="endpoint_process" AND process_name IN ("powershell.exe","pwsh.exe","cmd.exe","wmic.exe","winrs.exe","mstsc.exe","psexec.exe"))
| WHERE session_key IS NOT NULL AND session_key!="" AND session_key!="-"
| KEEP session_key,event_ms,tenant_id,principal_id,endpoint_id,kind,process_name,parent_name,command_line,record_id
| LOOKUP JOIN sonicwall-session-lookup ON session_key
| WHERE rhs_vpn_saml_enabled=="true" AND rhs_vpn_expected_saml=="true" AND rhs_vpn_auth_path=="alternate_verified" AND rhs_vpn_ms>=1793516400000 AND rhs_vpn_ms<1794072600000
| WHERE event_ms>=rhs_vpn_ms AND event_ms<=rhs_vpn_ms+3600000
| KEEP event_ms,tenant_id,session_key,rhs_vpn_ms,rhs_vpn_principal,principal_id,endpoint_id,kind,process_name,parent_name,command_line,record_id
| LIMIT 10000CrowdStrike
dataset="sonicwall_hunt"
| h4_ready="true"
| event_ms >= 1793516400000
| event_ms < 1794072600000
| kind="endpoint_admin_logon" OR (kind="endpoint_process" AND (process_name="powershell.exe" OR process_name="pwsh.exe" OR process_name="cmd.exe" OR process_name="wmic.exe" OR process_name="winrs.exe" OR process_name="mstsc.exe" OR process_name="psexec.exe"))
| session_key=* session_key!="" session_key!="-"
| select([@timestamp,session_key,event_ms,tenant_id,principal_id,endpoint_id,kind,process_name,parent_name,command_line,record_id])
| join(query={
dataset="sonicwall_hunt" h4_ready="true" kind="vpn_success" saml_enabled="true" expected_saml="true" auth_path="alternate_verified"
| event_ms >= 1793516400000
| event_ms < 1794072600000
| select([@timestamp,session_key,event_ms,principal_id])
| rhs_vpn_ms:=event_ms
| rhs_vpn_principal:=principal_id
},field=session_key,include=[rhs_vpn_ms,rhs_vpn_principal],mode=inner,max=200000,limit=200000,
start="1793516400000",end="1794072600000")
| delta_ms:=event_ms-rhs_vpn_ms
| delta_ms>=0
| delta_ms<=3600000
| select([event_ms,tenant_id,session_key,rhs_vpn_ms,rhs_vpn_principal,principal_id,endpoint_id,kind,process_name,parent_name,command_line,record_id])Microsoft KQL
let VPN = SonicWallHunt_CL
| where event_ms >= 1793516400000 and event_ms < 1794072600000
| where h4_ready=="true"
| where kind=="vpn_success" and saml_enabled=="true" and expected_saml=="true" and auth_path=="alternate_verified"
| project session_key,rhs_vpn_ms=event_ms,rhs_vpn_principal=principal_id;
SonicWallHunt_CL
| where event_ms >= 1793516400000 and event_ms < 1794072600000
| extend process_name=tolower(process_name)
| where h4_ready=="true"
| where kind=="endpoint_admin_logon" or (kind=="endpoint_process" and process_name in ("powershell.exe","pwsh.exe","cmd.exe","wmic.exe","winrs.exe","mstsc.exe","psexec.exe"))
| where isnotempty(session_key) and session_key!="-"
| project session_key,event_ms,tenant_id,principal_id,endpoint_id,kind,process_name,parent_name,command_line,record_id
| join kind=inner VPN on session_key
| where event_ms>=rhs_vpn_ms and event_ms<=rhs_vpn_ms+3600000
| project event_ms,tenant_id,session_key,rhs_vpn_ms,rhs_vpn_principal,principal_id,endpoint_id,kind,process_name,parent_name,command_line,record_idsession_key must link a tenant-qualified VPN session to endpoint evidence through verified tunnel leases, flows and device inventory, not public-IP equality. Elastic's lookup-mode sonicwall-session-lookup carries the VPN time, principal and three policy and authentication fields. The other three platforms join the session stream. Map process and parent names plus command lines from actual endpoint telemetry; administrative logons require independently verified privilege. These process names are generic leads, not published indicators. Recent sessions have incomplete one-hour follow-up; missing device mapping cannot clear them.
Decide what the evidence establishes
An alternate-path success establishes a policy discrepancy. It does not establish attacker identity or distinguish exploitation of this CVE from a configured fallback. Check the build and policy at the session time. A missing IdP match first needs a coverage explanation. A new address adds context; a confirmed administrative action adds consequence. An endpoint match is temporal association, not proof that the VPN user caused it. Preserve process trees, destinations and sessions before expanding containment. Legitimate support work can produce these leads.
What this means for your team
For an MSP, the important inventory connects the client, appliance, accepted session and business identity. Checking only the MFA dashboard misses the system that actually granted network access.
Sources
Inception Protection
Inception Protection is our managed detection and response service, with analysts reviewing endpoint, identity, email and cloud alerts around the clock.
Inception Foresight
The free Inception Foresight M365 Assessment reviews Microsoft 365 identity, email, sharing, device and audit settings and returns a prioritized remediation plan. It does not test SonicWall appliances or certify VPN remediation. Request the M365 Assessment.



