Skip to content

Comments

fix: public github release downloads should not be authenticated#27

Open
yeikel wants to merge 1 commit intodependabot:mainfrom
yeikel:fix/public-auth-calls
Open

fix: public github release downloads should not be authenticated#27
yeikel wants to merge 1 commit intodependabot:mainfrom
yeikel:fix/public-auth-calls

Conversation

@yeikel
Copy link

@yeikel yeikel commented Feb 4, 2026

The proxy should not assume that asset release downloads require authentication. These endpoints are public, and including a token can actually cause access to fail with an unauthorized error.

For additional context and analysis see #15 (comment)

Fixes #15

Logs:

Before this change

2026/02/04 06:50:39 proxy starting, commit: dev
2026/02/04 01:50:39 Listening (:1080)
2026/02/04 01:51:02 [002] HEAD https://services.gradle.org:443/distributions/gradle-9.2.0-bin.zip
2026/02/04 01:51:02 [002] 307 https://services.gradle.org:443/distributions/gradle-9.2.0-bin.zip
2026/02/04 01:51:02 [004] HEAD https://github.com:443/gradle/gradle-distributions/releases/download/v9.2.0/gradle-9.2.0-bin.zip
2026/02/04 01:51:02 [004] * authenticating git server request (host: github.com)
2026/02/04 01:51:02 [004] 302 https://github.com:443/gradle/gradle-distributions/releases/download/v9.2.0/gradle-9.2.0-bin.zip
2026/02/04 01:51:03 [006] HEAD https://objects.githubusercontent.com:443/github-production-release-asset-2e65be/696192900/59c24fc6-8617-4334-917a-58d539c557d3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=releaseassetproduction%2F20260204%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260204T065104Z&X-Amz-Expires=1800&X-Amz-Signature=f20b2f55b452f1b7ca94086a2c62f17bcba2b0ee382e77d322fdbd50a243e527&X-Amz-SignedHeaders=host&response-content-disposition=attachment%3B%20filename%3Dgradle-9.2.0-bin.zip&response-content-type=application%2Foctet-stream
2026/02/04 01:51:03 [006] 401 https://objects.githubusercontent.com:443/github-production-release-asset-2e65be/696192900/59c24fc6-8617-4334-917a-58d539c557d3?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=releaseassetproduction%2F20260204%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20260204T065104Z&X-Amz-Expires=1800&X-Amz-Signature=f20b2f55b452f1b7ca94086a2c62f17bcba2b0ee382e77d322fdbd50a243e527&X-Amz-SignedHeaders=host&response-content-disposition=attachment%3B%20filename%3Dgradle-9.2.0-bin.zip&response-content-type=application%2Foctet-stream

After this change

2026/02/04 06:49:02 proxy starting, commit: dev
2026/02/04 01:49:02 Listening (:1080)
2026/02/04 01:49:35 [002] HEAD https://services.gradle.org:443/distributions/gradle-9.2.0-bin.zip
2026/02/04 01:49:35 [002] 307 https://services.gradle.org:443/distributions/gradle-9.2.0-bin.zip
2026/02/04 01:49:35 [004] HEAD https://github.com:443/gradle/gradle-distributions/releases/download/v9.2.0/gradle-9.2.0-bin.zip
2026/02/04 01:49:35 [004] 302 https://github.com:443/gradle/gradle-distributions/releases/download/v9.2.0/gradle-9.2.0-bin.zip
2026/02/04 01:49:35 [006] HEAD https://release-assets.githubusercontent.com:443/github-production-release-asset/696192900/59c24fc6-8617-4334-917a-58d539c557d3?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-02-04T07%3A30%3A36Z&rscd=attachment%3B+filename%3Dgradle-9.2.0-bin.zip&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-02-04T06%3A30%3A32Z&ske=2026-02-04T07%3A30%3A36Z&sks=b&skv=2018-11-09&sig=kasSevSu%2BWrZDWMK1tepgTDuLhkDuakwTTnEBX2F4f4%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc3MDE5MTM3NywibmJmIjoxNzcwMTg3Nzc3LCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.3DIcTnpywlfoHQyUxPWmo9214Qe8zClbdFZTxtSNDmk&response-content-disposition=attachment%3B%20filename%3Dgradle-9.2.0-bin.zip&response-content-type=application%2Foctet-stream
2026/02/04 01:49:35 [006] 200 https://release-assets.githubusercontent.com:443/github-production-release-asset/696192900/59c24fc6-8617-4334-917a-58d539c557d3?sp=r&sv=2018-11-09&sr=b&spr=https&se=2026-02-04T07%3A30%3A36Z&rscd=attachment%3B+filename%3Dgradle-9.2.0-bin.zip&rsct=application%2Foctet-stream&skoid=96c2d410-5711-43a1-aedd-ab1947aa7ab0&sktid=398a6654-997b-47e9-b12b-9515b896b4de&skt=2026-02-04T06%3A30%3A32Z&ske=2026-02-04T07%3A30%3A36Z&sks=b&skv=2018-11-09&sig=kasSevSu%2BWrZDWMK1tepgTDuLhkDuakwTTnEBX2F4f4%3D&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmVsZWFzZS1hc3NldHMuZ2l0aHVidXNlcmNvbnRlbnQuY29tIiwia2V5Ijoia2V5MSIsImV4cCI6MTc3MDE5MTM3NywibmJmIjoxNzcwMTg3Nzc3LCJwYXRoIjoicmVsZWFzZWFzc2V0cHJvZHVjdGlvbi5ibG9iLmNvcmUud2luZG93cy5uZXQifQ.3DIcTnpywlfoHQyUxPWmo9214Qe8zClbdFZTxtSNDmk&response-content-disposition=attachment%3B%20filename%3Dgradle-9.2.0-bin.zip&response-content-type=application%2Foctet-stream

Comment on lines 352 to 355
func isGitHubReleaseDownload(path string) bool {
return strings.Contains(path, "/releases/download/")
}

Copy link
Author

@yeikel yeikel Feb 4, 2026

Choose a reason for hiding this comment

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

This approach doesn’t feel entirely safe, as it could also match URLs like myExample.com/releases/download/.

However, I didn’t see any reliable way to verify that the host is GitHub-related.

For example, github.com is obvious, but GitHub Enterprise and other environments are less straightforward

Copy link
Author

Choose a reason for hiding this comment

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

@JamieMagee I'd appreciate your input here and in the pull request altogether

Copy link
Member

Choose a reason for hiding this comment

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

I agree. A few possible options I can think of:

  • Scope this to only github.com (not a complete fix since GHES exists, but narrows the blast radius)
  • Instead of skipping auth on the initial request, handle the auth failure on the redirect target. Though that's trickier since it's a separate request through the proxy
  • Strip the Authorization header on redirect responses from known GitHub hosts (302 -> asset CDN) rather than preventing auth on the original request

Copy link
Author

@yeikel yeikel Feb 8, 2026

Choose a reason for hiding this comment

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

Strip the Authorization header on redirect responses from known GitHub hosts (302 -> asset CDN) rather than preventing auth on the original request

Unfortunately, this does not work because the redirect GitHub gives depends on whether you pass authentication or not. It is an interesting behavior/I ignore why that is:

HEAD request without auth: https://github.com:443/gradle/gradle-distributions/releases/download/v9.3.0/gradle-9.3.0-bin.zip → Redirects to https://release-assets.githubusercontent.com/github-production-release-asset..., which resolves correctly.

HEAD request with auth(it does not matter if it is valid): Same URL → Redirects to https://objects.githubusercontent.com/…, which doesn’t resolve and consistently returns 401.

Copy link
Author

Choose a reason for hiding this comment

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

I tested this on GitHub Enterprise, and the behavior is slightly different. In our environment, SAML/SSO is required, so public download URLs do not work outside of a browser session. I can only assume that even there, the download must be done using the GitHub API

Copy link
Author

@yeikel yeikel Feb 9, 2026

Choose a reason for hiding this comment

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

Scope this to only github.com (not a complete fix since GHES exists, but narrows the blast radius)

I updated it to scope it only for github.com. But as described above, in GHE this won't work because no client in GHE should try to reach public urls (at least not if using SSO). That said, I am not sure about all the combinations or deployment options

@yeikel yeikel force-pushed the fix/public-auth-calls branch 2 times, most recently from 4dd5055 to a745ec4 Compare February 4, 2026 14:26

// GitHub release download URLs are public
// and do not require authentication
if len(credsForRequest) != 0 && isGitHubReleaseDownload(r.URL.Path) {
Copy link
Author

@yeikel yeikel Feb 4, 2026

Choose a reason for hiding this comment

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

My attempt at preventing potential cross-type detection is to ensure that this is considered a git host and that we have stored credentials for it. I don't know if this is good enough

Copy link
Member

Choose a reason for hiding this comment

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

This worries me for private repos. If someone has a private GitHub repo with release assets, they need auth on the initial request to github.com to even get the 302 redirect URL. This returns nil for all release downloads, public or private.

The existing retry logic in HandleResponse handles 401/403/404 by stripping auth and retrying, but that only applies to the same request. The one failing here is the redirect target (objects.githubusercontent.com), which is a different request from the proxy's perspective.

Have you tested this against a private repo with release assets?

Copy link
Author

@yeikel yeikel Feb 8, 2026

Choose a reason for hiding this comment

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

Have you tested this against a private repo with release assets?

I tested this and it does not work in its current form. However, the behavior is consistent with GitHub’s documented expectations.

Artifacts from private repositories cannot be downloaded via "public" (what we can see from the browser) release asset URL (for example, https://github.com/gradle/gradle-distributions/releases/download/v9.3.0/gradle-9.3.0-bin.zip), even when authentication is provided. GitHub instead requires private release assets to be accessed through the GitHub API and downloaded using the ASSET-ID. In the proxy, the closest equivalent would be the github_api handler.

I may be mistaken, but from the proxy’s perspective this appears to be out of scope. Rather, the client (such as Dependabot Core) would need to be aware of this in advance and issue an API call instead.

See: https://github.com/orgs/community/discussions/47453

@yeikel yeikel force-pushed the fix/public-auth-calls branch 2 times, most recently from f8ef079 to 5d7b9c9 Compare February 9, 2026 00:43
@yeikel yeikel force-pushed the fix/public-auth-calls branch from 5d7b9c9 to 5ffa3af Compare February 9, 2026 00:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Investigate proxy issue preventing gradle wrapper url validation

2 participants