Skip to content

fix: read SSRF allowlist from NBY env var - #4

Open
OscarMoya wants to merge 6 commits into
allow-ip-rangesfrom
nby-ssrf-allowlist
Open

OscarMoya wants to merge 6 commits into
allow-ip-rangesfrom
nby-ssrf-allowlist

Conversation

@OscarMoya

@OscarMoya OscarMoya commented Oct 7, 2026 •

Copy link
Copy Markdown

Oathkeeper v26.2.1-ips-alpine refuses the Keto IP on clusters whose Service CIDR is 198.18.0.0/15 (+Orange PRE), so every remote_json rule (group management, branding) returns 500 "no such host". The v25 patch (Nov 2025) allowed 100.64.0.0/10 and 198.18.0.0/15. Upstream v26 moved the list from oryx/httpx/ssrf.go to oryx/ipx/ssrf.go, and 198.18.0.0/15 was lost on the way:

  • The 2026-06-26 rebase re-applied only 100.64.0.0/10 in Oathkeeper and Hydra. Kratos kept both.
  • The Keto image v26.2.1-ips was built from a commit that is on no GitHub branch. Its compiled binary also lacks 198.18.0.0/15.

Change (identical in all four forks)

  • New file oryx/ipx/ssrf_nby.go holds the lists. AllowInternalDialFunc in oryx/ipx/ssrf.go uses them: a 2-line change in the upstream file. ProhibitInternalDialFunc (strict client) is unchanged.
  • Env NBY_SSRF_ALLOWED_PREFIXES is the complete allowlist, comma-separated, IPv4 and IPv6. Non-empty replaces the default. Unset or empty keeps it. An invalid or IPv4-mapped prefix panics at startup, naming the env var.
  • The default is the private and reserved ranges a cluster may use: 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.31.196.0/24, 192.52.193.0/24, 192.88.99.0/24, 192.168.0.0/16, 192.175.48.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/4, 240.0.0.0/4, ::1/128, fc00::/7, 100::/64, 2001:db8::/32, 2620:4f:8000::/48. Public addresses stay allowed, as upstream. fc00::/7 still contains AWS IMDS over IPv6 (fd00:ec2::254), as upstream.
  • Never in the default: 169.254.0.0/16 (cloud metadata; upstream allowed it), 0.0.0.0/8 and ::/128 (local host), fe80::/10 (link-local), and the IPv6 ranges that embed an IPv4 address, because they would bypass the IPv4 list: ::ffff:0:0/96, 64:ff9b::/96, 64:ff9b:1::/48, 2001::/23, 2002::/16.

Guard against the next rebase

  • oryx/ipx/ssrf_nby_test.go pins the default list. It checks allowed and denied addresses, the override, invalid values and the wiring: 169.254.169.254 is refused before connecting, 198.18.0.1 is not. Each of these mutations fails it: ssrf.go reverted to the upstream list, the upstream list minus 169.254, 198.18/15 dropped, 224/4 dropped.
  • .github/workflows/nby-ssrf-allowlist.yml runs go test ./ipx/ in oryx/ on push to allow-ip-ranges* and nby-*, and on PRs into allow-ip-ranges*. Nothing ran the vendored oryx tests before.
  • go vet, go test -race ./ipx/ and the full binary build pass in all four forks.

Dependency fixes

govulncheck found these reachable in all four binaries, inherited from the upstream base:

  • golang.org/x/text v0.38.0 to v0.41.0: GO-2026-5970.
  • google.golang.org/grpc v1.81.1 to v1.83.2: GO-2026-6348, 6061, 6441, 6443. 6443 regressed in 1.83.0 and is fixed in 1.83.2.
  • go.opentelemetry.io/otel exporters v1.44.0 to v1.45.0: GO-2026-6505.
  • Raised at module level only: x/crypto v0.56.0, x/mod v0.40.0, x/net v0.58.0, mongo-driver v1.17.7. The go directive becomes 1.26.0 because the new x/ modules require it. A second commit adds the go.sum entries the raised x/tools and x/term need for the go.mod tool directives (goimports, buf, goveralls); go.mod is unchanged by it.
  • govulncheck has nothing fixable left. No fix exists for GO-2026-5932 (x/crypto/openpgp) and, in oathkeeper, the aws-sdk-go S3 crypto advisories (module level). Ory's own advisories (hydra GHSA-r9w3-57w2-gch2, oathkeeper GO-2026-4799/4804/4810, GO-2023-1747) are false positives: the forks' pseudo-versions sort below the fixes, and the fix commits are in the branches.

CI

Upstream Ory's CI fails on the same jobs: the image scanners fail on master of all four ory/* repos, and ory/kratos no longer has the CLI docs job.

Repo Fix
all four Pin kubescape/github-action to v3.0.21 by commit SHA. @main now runs Kubescape in its own container without the Docker socket, so it cannot see the image the job built.
oathkeeper .docker/Dockerfile-build copies the github.com/ory/rpctest replace module before go mod download, and copies oryx/go.sum to the right path. Upstream master has the same bug: the image never built. New .grype.yaml ignores 4 Oathkeeper self-advisories, scoped to the oathkeeper package, each with its fix commit.
hydra .grype.yml ignores GHSA-r9w3-57w2-gch2, scoped to github.com/ory/hydra/v2. Its fix commit 0b84568fffcc (v26.2.0) is in the branch. One "Run OIDC conformity tests" run ended INTERRUPTED in the conformance suite's browser automation. The same job passed on the earlier head that already had the dependency bump. It was re-run.
kratos "Build CLI docs" runs only when github.repository_owner == 'ory', the guard upstream uses for its upstream-only jobs. It publishes to ory/docs with the Ory bot token, and the floating ory/ci/docs/cli-next@master action no longer fits this clidoc version.

Verified

Images built from these PR heads and pushed to the registry: oathkeeper v26.2.1-ips3-alpine, hydra v26.2.1-ips3, keto v26.2.1-ips3, kratos v26.2.1-oidc-ips3.

  • On oscarmoyag (chart 26.1, the four Ory images overridden to ips3, the env var set empty): all four pods Ready with 0 restarts, running digests equal the pushed ones, NBY_SSRF_ALLOWED_PREFIXES present, no panic or "no such host" in the logs. Oathkeeper to Keto remote_json: GET /perms/manage/group/<id> 200, POST /perms/manage/group/<id>/user/<id> 201, and Oathkeeper logged granted=true for both rules.
  • Locally, on a 198.18.0.0/24 network: the old v26.2.1-ips-alpine reproduces "lookup ...: no such host" (500), ips3 returns 200, an override without 198.18 returns 500 again, and a bad value stops the container at startup.

Refs nbycomp/nearbyone-tracker#2591.

The v26 rebase re-applied our allowlist patch by hand and lost
198.18.0.0/15. Oathkeeper then failed every Keto check on clusters
whose Service CIDR is 198.18.0.0/15 (nearbyone-tracker#2591).

AllowInternalDialFunc now takes its prefixes from ssrf_nby.go:

- NBY_SSRF_ALLOWED_PREFIXES is the complete allowlist, comma
  separated, IPv4 and IPv6. Unset or empty keeps the default.
- The default holds the private and reserved ranges a cluster may
  use. It never allows 169.254.0.0/16, 0.0.0.0/8, fe80::/10 or IPv6
  ranges that embed an IPv4 address.
- An invalid or IPv4-mapped prefix panics at startup.

The patch lives in its own file so a rebase cannot drop it silently.
The test pins the default list and checks the override and the
wiring in ssrf.go. The nby-ssrf-allowlist workflow runs it on every
push to the fork branches.

Signed-off-by: OscarMoya <oscar.moya@nearbycomputing.com>
Upstream Format runs prettier, which rejects single-quoted strings.

Signed-off-by: OscarMoya <oscar.moya@nearbycomputing.com>
@OscarMoya
OscarMoya added this pull request to stack #5 October 7, 2026 16:05
govulncheck found these reachable in all four binaries, inherited
from the upstream base:

- golang.org/x/text v0.38.0 -> v0.41.0 (GO-2026-5970)
- google.golang.org/grpc v1.81.1 -> v1.83.2 (GO-2026-6348, 6061,
  6441, 6443; 6443 regressed in 1.83.0 and is fixed in 1.83.2)
- go.opentelemetry.io/otel/exporters v1.44.0 -> v1.45.0
  (GO-2026-6505)

Also raised, flagged at module level only: x/crypto v0.56.0, x/mod
v0.40.0, x/net v0.58.0, mongo-driver v1.17.7. Only the minimum fixed
versions were requested; the other modules moved as required, and
the go directive becomes 1.26.0 because the new x/ modules need it.

No fix exists yet for GO-2026-5932 (x/crypto/openpgp) and the
aws-sdk-go S3 crypto advisories (GO-2022-0635, GO-2022-0646).

Signed-off-by: OscarMoya <oscar.moya@nearbycomputing.com>
The raised golang.org/x/tools and x/term versions need checksums
for the tools declared in go.mod (goimports, buf, goveralls), which
the format, lint and test jobs run. Added with go list -deps tool;
go.mod is unchanged.

Signed-off-by: OscarMoya <oscar.moya@nearbycomputing.com>
Dockerfile-build ran go mod download without the module that the
github.com/ory/rpctest replace points to, so the image never built;
it also copied oryx/go.sum to proto/go.sum. Upstream master has the
same bug.

Grype then matches four of Oathkeeper's own advisories against the
fork's pseudo-version v0.40.2-0..., which sorts below the fixes. The
fix commits are in this branch, so .grype.yaml ignores them for the
oathkeeper package only.

Signed-off-by: OscarMoya <oscar.moya@nearbycomputing.com>
kubescape/github-action@main now runs Kubescape in its own container
without the Docker socket, so it cannot see the image the job just
built and falls back to Docker Hub (manifest unknown). v3.0.21 is a
Docker container action, which gets the socket, and it takes the
same inputs. Pinned by commit SHA.

Signed-off-by: OscarMoya <oscar.moya@nearbycomputing.com>
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.

1 participant