Skip to content

Export-AzRuleData can exit silently with no output: unreachable context guard, StrictMode filter aborts all contexts, bare return #3880

Description

Summary

Three defects in PSRule.Rules.Azure.psm1 compose so that Export-AzRuleData can exit successfully, silently, and with no output when the Azure context is missing or partially malformed. Downstream that becomes a clean, empty scan — a false negative on a security tool, which is the worst failure mode for this kind of check.

Verified against main (src/PSRule.Rules.Azure/PSRule.Rules.Azure.psm1) at time of filing. Line numbers are from that file.

1. Unreachable guard in FindAzureContext (line 703)

$context = @(GetAzureContext -ListAvailable:$listAvailable);
if ($Null -eq $context -and $context.Length -gt 0) {
    Write-Error -Message 'Could not find an existing context. Use Connect-AzAccount to establish a PowerShell context with Azure.';
    return;
}

$context is wrapped in @(...), so it is always an array and never $null. $Null -eq $context is therefore always $false, -and short-circuits, and the body is unreachable. The condition is also self-contradictory as written: it requires $context to be null and to have a positive length.

The actionable "Use Connect-AzAccount" error can never be emitted. The intent looks like:

if ($Null -eq $context -or $context.Length -eq 0) {

2. Whole filter pipeline inside one try, under Set-StrictMode -Version latest (lines 708-726)

The module sets Set-StrictMode -Version latest at line 8. FindAzureContext then does:

try {
    $filteredContext = @($context | ForEach-Object -Process {
            if (
            ($Null -eq $Tenant -or $Tenant.Length -eq 0 -or ($_.Tenant.Id -in $Tenant)) -and
            ($Null -eq $Subscription -or $Subscription.Length -eq 0 -or ($_.Subscription.Id -in $Subscription) -or ($_.Subscription.Name -in $Subscription))
            ) {
                $_;
            }
        })
    ...
    return $filteredContext;
}
catch {
    Write-Error -Message "Failed to filter contexts. Error: $_";
}

Under StrictMode, a single context missing .Tenant or .Subscription throws on property access. Because the try spans the entire pipeline and return $filteredContext sits inside it, that one bad context causes every context to be discarded — the function falls into catch and returns nothing at all, rather than skipping the offending entry.

Filtering per-item, or narrowing the try, would let one malformed context be skipped without destroying the rest.

3. Silent bare return in Export-AzRuleData (lines 86-88)

if ($Null -eq $contextSubscriptions -or $contextSubscriptions.Length -eq 0) {
    return;
}

Nothing is written to the error or warning stream. Combined with (1) and (2), the caller gets a successful exit code and an empty output directory with no diagnostic anywhere.

Combined effect

  1. No usable Azure context, or one malformed context present
  2. (2) discards all contexts and returns nothing
  3. (1) cannot fire, so the actionable error is never surfaced
  4. (3) returns silently, exit code 0, no output

Result: Export-AzRuleData reports success and exports nothing, and any downstream PSRule scan over that directory reports a clean result.

Impact

We hit this in a downstream tool that calls Export-AzRuleData and then scans the export directory. Every subscription scan came back clean and empty, with no error at any layer, which is indistinguishable from "no findings". For a security-assessment tool a silent false negative is materially worse than a loud failure.

Suggested fixes

  • Correct the guard to -or ... -eq 0 so it can actually fire
  • Filter contexts per-item so one malformed entry does not discard the whole set, or use StrictMode-safe property access in the filter predicate
  • Replace the bare return with a Write-Error (or at minimum Write-Warning) so an empty export is distinguishable from a clean one

Happy to open a PR if the maintainers would like these as one change or three.

Credit

Found by Haflidi Fridthjofsson (@haflidif) while testing against live Azure tenants, and diagnosed while investigating a downstream report at martinopedal/azure-analyzer#1215.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions