Skip to content

Allow the Nexus S3 blob store that packages.nuxeo.com redirects to - #291

Open
ataillefer wants to merge 1 commit into
dependabot:mainfrom
ataillefer:allowlist-nuxeo-nexus-s3-backend
Open

ataillefer wants to merge 1 commit into
dependabot:mainfrom
ataillefer:allowlist-nuxeo-nexus-s3-backend

Conversation

@ataillefer

Copy link
Copy Markdown

What are you trying to accomplish?

packages.nuxeo.com is already in the Maven defaults, but the entry is incomplete. Nexus 302-redirects every GET — metadata and artifacts alike, in both maven-public and maven-public-lts — to its S3 blob store on nuxeo-devtools-nexus-central.s3.eu-west-1.amazonaws.com, and that host is not allowlisted, so the redirect is blocked under proxy-egress-enforce:

proxy | [014] GET https://packages.nuxeo.com:443/repository/maven-public-lts/org/nuxeo/build/nuxeo-distribution-tools/maven-metadata.xml
proxy | [014] 302 https://packages.nuxeo.com:443/...
proxy | [016] GET https://nuxeo-devtools-nexus-central.s3.eu-west-1.amazonaws.com:443/storage/content/...
proxy | [016] * egress not allowlisted nuxeo-devtools-nexus-central.s3.eu-west-1.amazonaws.com
proxy | [016] 403 https://nuxeo-devtools-nexus-central.s3.eu-west-1.amazonaws.com:443/...
proxy | [016] Remote response: Forbidden

Dependabot then falls back to Maven Central, so artifacts mirrored there recover silently and only artifacts unique to this repository fail, surfacing as private_source_authentication_failure against packages.nuxeo.com. On nuxeo/nuxeo-lts that is 33 dependencies per run, across three release branches, every day since 2026-09-30. HEAD is served directly by Nexus without a redirect, which is why jar HEAD probes in the log return 200 while every metadata GET fails.

This adds the blob store host so the existing packages.nuxeo.com entry actually works.

The repository is public and anonymous. Following the redirect with plain curl and no credentials returns 200:

curl -sIL https://packages.nuxeo.com/repository/maven-public-lts/org/nuxeo/build/nuxeo-distribution-tools/maven-metadata.xml

The bucket is owned by Nuxeo and backs packages.nuxeo.com, Nuxeo's public distribution repository for the open-source Nuxeo Platform.

Anything you want to highlight for special attention from reviewers?

Why the exact form, and not a glob. AWS reserves no nuxeo-devtools- prefix, so any sibling name is registrable by anyone — nuxeo-devtools-nexus-evil and nuxeo-devtools-nexus-central-x both return 404 NoSuchBucket today. A nuxeo-devtools-*.s3.*.amazonaws.com pattern would therefore hand every job an attacker-registrable destination. Same reasoning as the julialang-storage-* entries, which have the identical <bucket>.s3.<region>.amazonaws.com shape. The exact entry is safe because the bucket is already registered: an unsigned GET returns 403 AccessDenied, not 404 NoSuchBucket, so the name cannot currently be taken by anyone else.

On ownership evidence. The bucket's TLS certificate is AWS's CN = *.s3-eu-west-1.amazonaws.com wildcard and is therefore not evidence of who controls it. The corroboration is that packages.nuxeo.com — valid certificate, CN = packages.nuxeo.com — is what issues the pre-signed URLs pointing at it, plus confirmation from Nuxeo. Flagging this explicitly rather than presenting the certificate as proof.

Allowlisting grants no access on its own. Every object requires a pre-signed URL that Nexus issues only after authorising the request; unsigned or tampered requests return 403. This matches the accepted jfrog-prod-* precedent, where the same buckets back private tenants.

Placement. Added alongside a8c-libs.s3.amazonaws.com in the exact-S3-bucket group rather than immediately next to packages.nuxeo.com, whose group comment ("verified anonymous: each returns 404 (not 401) for an absent artifact") does not describe a blob store. Happy to move it if you would rather keep the registry and its backend adjacent.

Alternative considered. Declaring the registry under registries: in dependabot.yml does not work here: dynamicHosts only derives redirect backends for ECR, via ecrHostPattern in egress_dynamic_hosts.go, so the S3 host would still be blocked. This is the same situation as #285.

How will you know you've accomplished your goal?

Reproduction of the block, before the change:

curl -sI https://packages.nuxeo.com/repository/maven-public-lts/org/nuxeo/build/nuxeo-distribution-tools/maven-metadata.xml
# HTTP/2 302, location: https://nuxeo-devtools-nexus-central.s3.eu-west-1.amazonaws.com/storage/content/...

Affected job log: https://github.com/nuxeo/nuxeo-lts/actions/runs/36932442506/job/110604806942 — 589 blocked requests, all for that one host.

Covered by tests in TestEgressAllowlist_PublicRegistriesThirdWaveAllowed, where packages.nuxeo.com is already asserted:

  • allowed on a real blob path
  • sibling bucket nuxeo-devtools-nexus-evil.s3.eu-west-1.amazonaws.com stays blocked
  • cross-region nuxeo-devtools-nexus-central.s3.us-east-1.amazonaws.com stays blocked
  • evil.nuxeo-devtools-nexus-central.s3.eu-west-1.amazonaws.com stays blocked, catching a later widening to a leading-dot entry

The existing path-style apex probes (s3.amazonaws.com, s3.us-east-1.amazonaws.com) already guard the rest.

Checklist

  • I have run the complete test suite to ensure all tests and linters pass.
  • I have thoroughly tested my code changes to ensure they work as expected, including adding additional tests for new functionality.
  • I have written clear and descriptive commit messages.
  • I have provided a detailed description of the changes in the pull request, including the problem it addresses, how it fixes the problem, and any relevant details about the implementation.
  • I have ensured that the code is well-documented and easy to understand.

Note: script/test passes in full. golangci-lint could not be run locally — its released image is built with Go 1.25 while the repo targets 1.26 — so gofmt, go vet and yamllint -c .yamllint.yaml were run instead and are clean. CI will cover the linter.

packages.nuxeo.com is already in the Maven defaults, but the entry is
incomplete: Nexus 302-redirects every download to its S3 blob store on
nuxeo-devtools-nexus-central.s3.eu-west-1.amazonaws.com, which is
blocked under proxy-egress-enforce.

Listed as an exact virtual-hosted bucket, never a glob: "nuxeo-devtools-"
is not a reserved AWS namespace, so any sibling name is registrable by
anyone and a glob over the bucket or the region would match an
attacker-controlled bucket.

Co-authored-by: Claude <noreply@anthropic.com>
@ataillefer
ataillefer requested a review from a team as a code owner October 2, 2026 10:18
Copilot AI balanced review requested due to automatic review settings October 2, 2026 10:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The narrowly scoped host entry follows existing security conventions and has comprehensive boundary tests.

Review effort: Balanced
Findings: None

What changed in this PR

Adds Nuxeo’s exact S3 blob-store host so Maven/Gradle requests can follow redirects from packages.nuxeo.com.

Changes:

  • Adds the exact regional S3 hostname to JVM defaults.
  • Tests allowed access and blocks sibling, cross-region, and child hosts.
File Description
internal/​handlers/​egress_allowlist_defaults.yaml Adds the exact Nuxeo S3 backend host.
internal/​handlers/​egress_allowlist_test.go Adds positive and anti-widening regression coverage.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

2 participants