Skip to content

Security Enforcement for Trusted Registries: Only allow module restore from trusted registries#19395

Open
jiangmingzhe wants to merge 2 commits intoAzure:mainfrom
jiangmingzhe:mingzhejiang/module-restore-guard
Open

Security Enforcement for Trusted Registries: Only allow module restore from trusted registries#19395
jiangmingzhe wants to merge 2 commits intoAzure:mainfrom
jiangmingzhe:mingzhejiang/module-restore-guard

Conversation

@jiangmingzhe
Copy link
Copy Markdown
Member

@jiangmingzhe jiangmingzhe commented Apr 11, 2026

Description: Block credential exfiltration via untrusted OCI registry restore

Problem

Opening an untrusted .bicep file triggers automatic OCI module restore, which sends Azure credentials to any referenced registry — including attacker-controlled ones — via the authenticate challenge. Simply opening a file is sufficient to exfiltrate credentials.

Solution

A registry trust allowlist enforced before any network I/O. Restore is blocked entirely for registries not on the list — no connection, no credential challenge.

Built-in trusted registries (*.azurecr.io, *.azurecr.cn, *.azurecr.us, mcr.microsoft.com, mcr.azure.cn, ghcr.io) are hardcoded. Users extend the list via security.trustedRegistries in bicepconfig.json.

Two new diagnostics: BCP446 (registry not trusted) and BCP447 (invalid pattern in config). Invalid patterns fail closed — all restore blocked until fixed.

Trust is checked against the literal hostname string in the source file. No DNS resolution is performed, preventing DNS rebinding attacks.

Checklist

Microsoft Reviewers: Open in CodeFlow

"*.azurecr.us",
"mcr.microsoft.com",
"mcr.azure.cn",
"ghcr.io",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will only work once the ORAS .net SDK change is merged to main, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix is independent of any ORAS SDK change. The trust check in OciArtifactRegistry.RestoreArtifacts runs before the ORAS SDK is ever called. The registries are blocked at the Bicep layer if they are untrusted and the SDK never sees them. The built-in list works purely through Bicep's own hostname matching.

/// Validates a single trusted registry pattern string.
/// Returns null if the pattern is valid, or an error message string if it is invalid.
/// </summary>
public static string? ValidateRegistryPattern(string pattern)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any libraries we can use for this validation and host matching?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't found any library that can do the matching out of the box yet. I checked the System.Uri library but it requires a scheme (like "https://") to construct the hostname and doesn't accept ".azurecr.io" hostnames with wildcards. Also some of the hostname match checks make it hard to adopt a library, and manual checks may still be needed. For example:
Accept "
.azurecrl.io" and reject "*.com",
Match "contoso.azurecr.io" against *.azurecr.io", but does not match "azurecr.io" against *.azurecr.io"

/// <see cref="GetConfiguration"/> re-scan the file system. Useful in tests where the
/// virtual file system is modified between compilation runs.
/// </summary>
void PurgeLookupCache() { }
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we can avoid exposing implementation details through the interface. If the test needs to reset the configuration cache, we could instead cast the interface to ConfigurationManager. A better approach might be to inject IConcurrentCache into ConfigurationManager, and let the tests clear the cache via IConcurrentCache.TryRemove.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants