{"record":{"id":"72d72269d97edf9b","repo":"microsoft/aspire","slug":"credential-bearing-http-sources-cannot-be-persisted","errorCode":null,"errorMessage":"Credential-bearing HTTP sources cannot be persisted.","messagePattern":"Credential-bearing HTTP sources cannot be persisted\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Packaging/PackageSourceOverrideMappings.cs","lineNumber":49,"sourceCode":"    public static string? GetMissingLocalDirectory(string source)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(source);\n\n        var sourceKind = ClassifySource(source, out var localDirectory);\n        if (sourceKind is PackageSourceKind.Http)\n        {\n            return null;\n        }\n\n        return Directory.Exists(localDirectory) ? null : localDirectory;\n    }\n\n    public static PackageMapping[] Create(string packageSourceOverride, PackageChannel? requestedChannel, string? nugetServiceIndexOverride)\n    {\n        ArgumentException.ThrowIfNullOrWhiteSpace(packageSourceOverride);\n        if (HasCredentialMaterial(packageSourceOverride))\n        {\n            throw new ArgumentException(\"Credential-bearing HTTP sources cannot be persisted.\", nameof(packageSourceOverride));\n        }\n\n        var mappings = new List<PackageMapping>\n        {\n            new(\"Aspire*\", packageSourceOverride)\n        };\n\n        if (requestedChannel?.Mappings is not null)\n        {\n            foreach (var mapping in requestedChannel.Mappings)\n            {\n                if (mapping.PackageFilter.StartsWith(\"Aspire\", StringComparison.OrdinalIgnoreCase))\n                {\n                    continue;\n                }\n\n                mappings.Add(mapping);\n            }","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Packaging/PackageSourceOverrideMappings.cs#L31-L67","documentation":"PackageSourceOverrideMappings.Create validates that a package source override URL does not embed credentials (userinfo in the URL or query-string keys/access tokens) because those mappings are persisted, which would leak secrets to disk. Any credential-bearing HTTP source is rejected with ArgumentException naming the packageSourceOverride parameter.","triggerScenarios":"Passing a source URL like https://user:pat@pkgs.example.com/v3/index.json or one containing ?api-key=... / ?key=... to Create (e.g. via ASPIRE_CLI_PACKAGE_SOURCE_OVERRIDE or CLI packaging setup).","commonSituations":"Pasting an authenticated Azure Artifacts or MyGet feed URL that includes a PAT; copying a URL from a browser session that appended a token query parameter.","solutions":["Strip credentials from the URL and pass only the plain https source (https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json).","Provide credentials out-of-band via a NuGet.config source entry with %VARIABLE% credential providers, not the override.","Use a credential provider (e.g. `dotnet nuget update source` with stored creds or the Artifacts credential provider).","If local-only testing requires credentials, use a non-persisted mechanism instead of the package source override mapping."],"exampleFix":"// before\nvar mappings = PackageSourceOverrideMappings.Create(\n    \"https://user:pat123@pkgs.dev.azure.com/org/_packaging/feed/nuget/v3/index.json\", channel, null);\n// after\nvar mappings = PackageSourceOverrideMappings.Create(\n    \"https://pkgs.dev.azure.com/org/_packaging/feed/nuget/v3/index.json\", channel, null);","handlingStrategy":"validation","validationCode":"if (Uri.TryCreate(source, UriKind.Absolute, out var uri) && !string.IsNullOrEmpty(uri.UserInfo))\n    throw new ArgumentException(\"Source URL must not embed credentials.\");\nif (source.Contains(\"key=\") || source.Contains(\"api-key=\"))\n    throw new ArgumentException(\"Source URL must not contain query-string credentials.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    var mappings = PackageSourceOverrideMappings.Create(source, channel, null);\n}\ncatch (ArgumentException ex)\n{\n    Console.Error.WriteLine(\"Remove credentials from the package source URL; use a credential provider instead.\");\n}","preventionTips":["Always use credential providers instead of URL-embedded PATs","Scan override URLs for '@' userinfo and token query params before passing","Store feed credentials in user-level NuGet config or env-based providers"],"tags":["nuget","security","credentials","argument-validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}