Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ hosted in Maven.
| - | - |
| Version | Required string. The version of the Java library that should be downloaded from Maven. Defaults to `true`. |
| Repository | Optional string. Specifies Maven repository to use. Supported values are `Central`, `Google`, or an `https` URL to a Maven repository. Defaults to `Central`. |
| AllowInsecureHttp | Optional boolean. When `Repository` is an `http://` URL, this must be set to `true` to allow the insecure connection. Defaults to `false`. Using HTTPS is strongly recommended for supply-chain security. |
| Bind | Optional boolean. Specifies whether the Java library should have a C# binding generated for it. Defaults to `true`. |
| Pack | Optional boolean. Specifies whether the Java library should be included in the project output. Defaults to `true`. |

Expand Down
3 changes: 3 additions & 0 deletions Documentation/docs-mobile/building-apps/build-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ The following MSBuild metadata are supported:
- `%(Version)`: Required version of the Java library referenced by `%(Include)`.
- `%(Repository)`: Optional Maven repository to use. Supported values are `Central` (default),
`Google`, or an `https` URL to a Maven repository.
- `%(AllowInsecureHttp)`: Optional boolean. When `%(Repository)` is an `http://` URL, this must be
set to `true` to allow the insecure connection. Defaults to `false`. Using HTTPS is strongly
recommended for supply-chain security.

The `<AndroidMavenLibrary>` item is translated to
[`AndroidLibrary`](#androidlibrary), so any metadata supported by
Expand Down
1 change: 1 addition & 0 deletions Documentation/docs-mobile/messages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ Either change the value in the AndroidManifest.xml to match the $(SupportedOSPla
+ [XA4248](xa4248.md): Could not find NuGet package '{nugetId}' version '{version}' in lock file. Ensure NuGet Restore has run since this `<PackageReference>` was added.
+ [XA4235](xa4249.md): Maven artifact specification '{artifact}' is invalid. The correct format is 'group_id:artifact_id:version'.
+ [XA4250](xa4250.md): Manifest-referenced type '{type}' was not found in any scanned assembly. It may be a framework type.
+ [XA4252](xa4252.md): Insecure HTTP Maven repository URL '{url}' is not allowed. Use an HTTPS URL, or set AllowInsecureHttp="true" metadata on the item to override this check.
+ XA4300: Native library '{library}' will not be bundled because it has an unsupported ABI.
+ [XA4301](xa4301.md): Apk already contains the item `xxx`.
+ [XA4302](xa4302.md): Unhandled exception merging \`AndroidManifest.xml\`: {ex}
Expand Down
43 changes: 43 additions & 0 deletions Documentation/docs-mobile/messages/xa4252.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title: .NET for Android error XA4252
description: XA4252 error code
ms.date: 05/15/2026
f1_keywords:
- "XA4252"
---

# .NET for Android error XA4252

## Example message

```
error XA4252: Insecure HTTP Maven repository URL 'http://repo.example.com/maven2/' is not allowed. Use an HTTPS URL, or set AllowInsecureHttp="true" metadata on the item to override this check.
```

## Issue

An `<AndroidMavenLibrary>` item specifies a Maven repository URL using `http://` instead of `https://`.
Downloading artifacts over plain HTTP is a security risk because the connection is not encrypted and is
vulnerable to man-in-the-middle attacks and supply-chain compromise.

This check aligns with default behavior in Gradle (`allowInsecureProtocol`) and Maven (`<blocked>http://*</blocked>`)
for defense in depth and supply-chain hardening.

## Solution

Use an HTTPS URL for the Maven repository whenever possible:

```xml
<ItemGroup>
<AndroidMavenLibrary Include="com.example:mylib" Version="1.0.0" Repository="https://repo.example.com/maven2/" />
</ItemGroup>
```

If the repository does not support HTTPS and you understand the security implications,
set `AllowInsecureHttp="true"` to explicitly opt in to insecure HTTP:

```xml
<ItemGroup>
<AndroidMavenLibrary Include="com.example:mylib" Version="1.0.0" Repository="http://repo.example.com/maven2/" AllowInsecureHttp="true" />
</ItemGroup>
```

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,11 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS
<value>Type '{0}' uses [JniAddNativeMethodRegistrationAttribute], which is not supported by the trimmable type map. To work around this, do not target the trimmable type map (for example, by switching to the 'llvm-ir' type map implementation), and please report this scenario at https://github.com/dotnet/android/issues so the team can evaluate whether to support it.</value>
<comment>The following are literal names and should not be translated: JniAddNativeMethodRegistrationAttribute, llvm-ir.
{0} - Fully-qualified managed type name</comment>
</data>
<data name="XA4252" xml:space="preserve">
<value>Insecure HTTP Maven repository URL '{0}' is not allowed. Use an HTTPS URL, or set AllowInsecureHttp="true" metadata on the item to override this check.</value>
<comment>The following are literal names and should not be translated: HTTP, HTTPS, Maven, AllowInsecureHttp
Comment thread
jonathanpeppers marked this conversation as resolved.
{0} - The insecure HTTP URL</comment>
</data>
<data name="XA0142" xml:space="preserve">
<value>Command '{0}' failed.\n{1}</value>
Expand Down
9 changes: 8 additions & 1 deletion src/Xamarin.Android.Build.Tasks/Tasks/MavenDownload.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,14 @@ public async override System.Threading.Tasks.Task RunTaskAsync ()
_ => null
};

if (repo is null && type.StartsWith ("http", StringComparison.OrdinalIgnoreCase)) {
if (repo is null && Uri.TryCreate (type, UriKind.Absolute, out var uri) &&
(uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)) {
if (uri.Scheme == Uri.UriSchemeHttp &&
!string.Equals (item.GetMetadataOrDefault ("AllowInsecureHttp", "false"), "true", StringComparison.OrdinalIgnoreCase)) {
Log.LogCodedError ("XA4252", Properties.Resources.XA4252, type);
return null;
}

using var hasher = SHA256.Create ();
var hash = hasher.ComputeHash (Encoding.UTF8.GetBytes (type));
var cache_name = Convert.ToBase64String (hash);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,41 @@ public async Task UnknownRepository ()
Assert.AreEqual ("Unknown Maven repository: 'bad-repo'.", engine.Errors [0].Message);
}

[Test]
public async Task InsecureHttpRepository_Blocked ()
{
var engine = new MockBuildEngine (TestContext.Out, new List<BuildErrorEventArgs> ());
var task = new MavenDownload {
BuildEngine = engine,
AndroidMavenLibraries = [CreateMavenTaskItem ("com.google.android.material:material", "1.0.0", "http://repo.example.com/maven2/")],
};

await task.RunTaskAsync ();

Assert.AreEqual (1, engine.Errors.Count);
Assert.AreEqual ("Insecure HTTP Maven repository URL 'http://repo.example.com/maven2/' is not allowed. Use an HTTPS URL, or set AllowInsecureHttp=\"true\" metadata on the item to override this check.", engine.Errors [0].Message);
}

[Test]
public async Task InsecureHttpRepository_AllowedWithOptIn ()
{
var engine = new MockBuildEngine (TestContext.Out, new List<BuildErrorEventArgs> ());
var item = CreateMavenTaskItem ("com.example:dummy", "1.0.0", "http://repo.example.com/maven2/");
item.SetMetadata ("AllowInsecureHttp", "true");

var task = new MavenDownload {
BuildEngine = engine,
MavenCacheDirectory = Path.GetTempPath (),
AndroidMavenLibraries = [item],
};

await task.RunTaskAsync ();

// Should bypass the XA4252 insecure HTTP check and attempt the download, which fails with XA4236
Assert.AreEqual (1, engine.Errors.Count);
Assert.AreEqual ("XA4236", engine.Errors [0].Code, "Expected a download error (XA4236), not a security error (XA4252)");
}

[Test]
public async Task UnknownArtifact ()
{
Expand Down