Skip to content

Commit a7d7932

Browse files
Network - 25413 - Sensitive data exfiltration through file transfers is prevented by network content filtering policies (#1047)
* Network - 25413 * Updated * code Refactored * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Feedback Addressed --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent cb6cc13 commit a7d7932

2 files changed

Lines changed: 215 additions & 0 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Without network content filtering through file policies, threat actors can exfiltrate data to unsanctioned destinations through browsers, applications, add-ins, and APIs. When file policies are not configured, threat actors exploit unmanaged cloud applications and generative AI tools as exfiltration channels for sensitive information.
2+
3+
**Remediation action**
4+
5+
Follow these steps to configure file policy protection:
6+
7+
- [Configure web content filtering policies in Global Secure Access, which covers the foundational approach for creating filtering policies including file policies](https://learn.microsoft.com/en-us/entra/global-secure-access/how-to-configure-web-content-filtering)
8+
- [Create and manage security profiles that group filtering policies for enforcement through Conditional Access](https://learn.microsoft.com/en-us/entra/global-secure-access/concept-traffic-forwarding)
9+
- [Link security profiles to Conditional Access policies for user-aware and context-aware enforcement of network security policies](https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-conditional-access-session)
10+
- [Deploy the Global Secure Access client on end-user devices to enable traffic acquisition and policy enforcement](https://learn.microsoft.com/en-us/entra/global-secure-access/how-to-install-windows-client)
11+
12+
<!--- Results --->
13+
%TestResult%
Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
<#
2+
.SYNOPSIS
3+
Sensitive data exfiltration through file transfers is prevented by network content filtering policies.
4+
.DESCRIPTION
5+
Verifies that file policies are configured in Global Secure Access and enforced through filtering profiles.
6+
The test passes if file policies exist and are enforced either through the Baseline Profile or through
7+
Security Profiles assigned to Conditional Access policies.
8+
#>
9+
10+
function Test-Assessment-25413 {
11+
[ZtTest(
12+
Category = 'Global Secure Access',
13+
ImplementationCost = 'High',
14+
MinimumLicense = ('Entra_Premium_Internet_Access'),
15+
Pillar = 'Network',
16+
RiskLevel = 'High',
17+
SfiPillar = 'Protect networks',
18+
TenantType = ('Workforce'),
19+
TestId = 25413,
20+
Title = 'Sensitive data exfiltration through file transfers is prevented by network content filtering policies',
21+
UserImpact = 'Medium'
22+
)]
23+
[CmdletBinding()]
24+
param()
25+
26+
# Define constants
27+
[int]$BASELINE_PROFILE_PRIORITY = 65000
28+
29+
#region Data Collection
30+
Write-PSFMessage '🟦 Start' -Tag Test -Level VeryVerbose
31+
32+
$activity = 'Checking file policy configuration for data exfiltration prevention'
33+
Write-ZtProgress -Activity $activity -Status 'Querying file policies'
34+
35+
# Step 1: Get file policies (undocumented endpoint - handle errors gracefully)
36+
$filePolicies = $null
37+
$errorMsg = $null
38+
try {
39+
$filePolicies = Invoke-ZtGraphRequest -RelativeUri 'networkAccess/filePolicies' -ApiVersion beta
40+
}
41+
catch {
42+
$errorMsg = $_.Exception.Message
43+
Write-PSFMessage $_.Exception.Message -Tag Test -Level Error
44+
}
45+
46+
# Step 2: Get filtering profiles with linked policies
47+
Write-ZtProgress -Activity $activity -Status 'Querying filtering profiles and linked policies'
48+
$filteringProfiles = $null
49+
try {
50+
$filteringProfiles = Invoke-ZtGraphRequest -RelativeUri 'networkAccess/filteringProfiles' -QueryParameters @{
51+
'$select' = 'id,name,description,state,version,priority'
52+
'$expand' = 'policies($select=id,state;$expand=policy($select=id,name,version))'
53+
} -ApiVersion beta
54+
}
55+
catch {
56+
if ($null -eq $errorMsg) {
57+
$errorMsg = $_.Exception.Message
58+
}
59+
Write-PSFMessage $_.Exception.Message -Tag Test -Level Error
60+
}
61+
62+
# Step 3: Get all Conditional Access policies
63+
Write-ZtProgress -Activity $activity -Status 'Querying Conditional Access policies'
64+
$allCAPolicies = Get-ZtConditionalAccessPolicy
65+
66+
# Collect all linked profiles
67+
$allLinkedProfiles = @()
68+
foreach ($filePolicy in $filePolicies) {
69+
$linkedProfiles = Find-ZtProfilesLinkedToPolicy -PolicyId $filePolicy.id -FilteringProfiles $filteringProfiles -CAPolicies $allCAPolicies -BaselinePriority $BASELINE_PROFILE_PRIORITY -PolicyLinkType 'filePolicyLink' -PolicyRules $filePolicy
70+
71+
foreach ($profileLink in $linkedProfiles) {
72+
$allLinkedProfiles += [PSCustomObject]@{
73+
ProfileId = $profileLink.ProfileId
74+
ProfileName = $profileLink.ProfileName
75+
ProfileType = $profileLink.ProfileType
76+
ProfileState = $profileLink.ProfileState
77+
ProfilePriority = $profileLink.ProfilePriority
78+
PolicyLinkState = $profileLink.PolicyLinkState
79+
PassesCriteria = $profileLink.PassesCriteria
80+
CAPolicy = $profileLink.CAPolicy
81+
}
82+
}
83+
}
84+
85+
#endregion Data Collection
86+
87+
#region Assessment Logic
88+
# Handle API errors early
89+
if ($errorMsg) {
90+
$passed = $false
91+
$testResultMarkdown = "❌ Unable to query Global Secure Access API endpoints. This may indicate the feature is not available in your tenant or the API has changed. Error: $errorMsg"
92+
}
93+
# Pass if any profile passes criteria (enabled baseline OR enabled security profile with CA)
94+
elseif (($allLinkedProfiles | Where-Object { $_.PassesCriteria -and $_.ProfileState -eq 'enabled' -and $_.PolicyLinkState -eq 'enabled' }).Count -gt 0) {
95+
$passed = $true
96+
$testResultMarkdown = @"
97+
✅ File policies are configured and actively enforced through a filtering profile, protecting against data exfiltration through unmonitored file transfers.
98+
99+
%TestResult%
100+
"@
101+
}
102+
elseif ($null -eq $filePolicies -or $filePolicies.Count -eq 0) {
103+
$passed = $false
104+
$testResultMarkdown = "❌ No file policy is configured. File transfers are unmonitored and the organization is exposed to data exfiltration risk.`n`n%TestResult%"
105+
}
106+
else {
107+
$passed = $false
108+
$testResultMarkdown = "❌ File policies are either not configured or not linked to an active filtering profile, leaving file transfers unmonitored and exposing the organization to data exfiltration risk.`n`n%TestResult%"
109+
}
110+
111+
#endregion Assessment Logic
112+
113+
#region Report Generation
114+
$mdInfo = ''
115+
116+
# Table 1: File Policy Configuration
117+
if ($filePolicies -and $filePolicies.Count -gt 0) {
118+
$table1Title = 'File Policy Configuration'
119+
$table1Link = 'https://entra.microsoft.com/#view/Microsoft_Azure_Network_Access/SecurityFiltering.ReactView'
120+
121+
$table1Template = @'
122+
123+
## [{0}]({1})
124+
125+
| File Policy Name | Default Action |
126+
| :--------------- | :------------- |
127+
{2}
128+
'@
129+
130+
$table1Rows = ''
131+
foreach ($fp in $filePolicies) {
132+
$fpName = Get-SafeMarkdown -Text $fp.name
133+
$defaultAction = if ($fp.settings.defaultAction) { $fp.settings.defaultAction } else { 'N/A' }
134+
$fpLink = "https://entra.microsoft.com/#view/Microsoft_Azure_Network_Access/EditFilePolicyMenuBlade.MenuView/~/basics/policyId/$($fp.id)"
135+
$table1Rows += "| [$fpName]($fpLink) | $defaultAction |`n"
136+
}
137+
138+
$mdInfo += $table1Template -f $table1Title, $table1Link, $table1Rows
139+
}
140+
141+
# Table 2: Filtering Profile Linkage (unified - baseline and security profiles)
142+
if ($allLinkedProfiles.Count -gt 0) {
143+
$table2Title = 'Filtering Profile Linkage'
144+
$table2Link = 'https://entra.microsoft.com/#view/Microsoft_Azure_Network_Access/SecurityProfiles.ReactView'
145+
146+
$table2Template = @'
147+
148+
## [{0}]({1})
149+
150+
| Linked Profile Name | Profile State | Policy Link State |
151+
| :------------------ | :------------ | :---------------- |
152+
{2}
153+
'@
154+
155+
$table2Rows = ''
156+
foreach ($profile in ($allLinkedProfiles | Sort-Object -Property ProfilePriority)) {
157+
$profileLink = "https://entra.microsoft.com/#view/Microsoft_Azure_Network_Access/EditProfileMenuBlade.MenuView/~/basics/profileId/$($profile.ProfileId)"
158+
$profileName = Get-SafeMarkdown -Text $profile.ProfileName
159+
$table2Rows += "| [$profileName]($profileLink) | $($profile.ProfileState) | $($profile.PolicyLinkState) |`n"
160+
}
161+
162+
$mdInfo += $table2Template -f $table2Title, $table2Link, $table2Rows
163+
}
164+
165+
# Table 3: Conditional Access Enforcement
166+
$caPoliciesForReport = @($allLinkedProfiles.CAPolicy | Where-Object { $null -ne $_ } | Sort-Object -Property Id -Unique)
167+
168+
if ($caPoliciesForReport.Count -gt 0) {
169+
$table3Title = 'Conditional Access Enforcement'
170+
$table3Link = 'https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/ConditionalAccessBlade/~/Policies'
171+
172+
$table3Template = @'
173+
174+
## [{0}]({1})
175+
176+
| CA Policy Name | CA Policy State |
177+
| :------------- | :-------------- |
178+
{2}
179+
'@
180+
181+
$table3Rows = ''
182+
foreach ($ca in ($caPoliciesForReport | Sort-Object -Property DisplayName)) {
183+
$caLink = "https://entra.microsoft.com/#view/Microsoft_AAD_ConditionalAccess/PolicyBlade/policyId/$($ca.Id)"
184+
$caName = Get-SafeMarkdown -Text $ca.DisplayName
185+
$table3Rows += "| [$caName]($caLink) | $($ca.State) |`n"
186+
}
187+
188+
$mdInfo += $table3Template -f $table3Title, $table3Link, $table3Rows
189+
}
190+
191+
$testResultMarkdown = $testResultMarkdown -replace '%TestResult%', $mdInfo
192+
193+
#endregion Report Generation
194+
195+
$params = @{
196+
TestId = '25413'
197+
Status = $passed
198+
Result = $testResultMarkdown
199+
}
200+
201+
Add-ZtTestResultDetail @params
202+
}

0 commit comments

Comments
 (0)