Skip to content

server: validate forwarded PD hosts before dialing - #11069

Open
rleungx wants to merge 8 commits into
tikv:masterfrom
rleungx:fix-forwarded-host-ssrf-master
Open

server: validate forwarded PD hosts before dialing#11069
rleungx wants to merge 8 commits into
tikv:masterfrom
rleungx:fix-forwarded-host-ssrf-master

Conversation

@rleungx

@rleungx rleungx commented Jul 30, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: close #11070

The pd-forwarded-host gRPC metadata is controlled by the caller, but PD previously used it as a dial target without verifying that it is the current PD leader. This could make PD establish outbound gRPC connections to attacker-selected addresses.

What is changed and how does it work?

server: validate forwarded PD hosts before dialing

Restrict forwarding targets supplied through gRPC metadata to the advertised client URLs of the current PD leader. Keep internally discovered TSO, Scheduling, and Resource Manager targets on the existing delegate-client path.
  • Validate the metadata target against the locally cached current PD leader before dialing; this does not call GetMembers or query etcd.
  • Return InvalidArgument for non-leader targets and Unavailable when no leader is available.
  • Validate TSO metadata once per incoming stream and reuse the validated connection, preserving existing streams across a leader change.
  • Apply the validation to unary, TSO, ReportBuckets, RegionHeartbeat, and PD metadata Resource Manager forwarding paths.

Check List

Tests

  • Integration test
    • Verify unary and TSO requests reject a non-member forwarding target.
    • Verify a current PD follower is also rejected as a forwarding target.
    • Verify the target TCP listener receives no connection.
    • Verify normal leader forwarding and the existing leader-change behavior still work.

Code changes

  • Has the configuration change
  • Has HTTP APIs changed
  • Has persistent data change

Side effects

  • Possible performance regression
  • Increased code complexity
  • Breaking backward compatibility

Related changes

  • Need to cherry-pick to the release branch

Release note

Reject `pd-forwarded-host` gRPC forwarding targets that are not advertised by the current PD leader.

Summary by CodeRabbit

  • Bug Fixes
    • Improved forwarded request routing to use only the current PD leader’s advertised client addresses.
    • Rejects requests targeting follower or unknown hosts with a clear invalid-argument error.
    • Returns an unavailable error when no usable PD leader is available.
    • Reuses forwarded connections during TSO streams for more consistent handling.

@ti-chi-bot ti-chi-bot Bot added do-not-merge/needs-linked-issue release-note Denotes a PR that will be considered when it comes time to generate release notes. dco-signoff: yes Indicates the PR's author has signed the dco. size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

PD forwarding now validates forwarded hosts against the current PD leader’s advertised client URLs. Unary, TSO, bucket, region heartbeat, and metadata-write paths use the validated delegate client. TSO streams reuse one connection, and tests cover rejected targets.

Changes

PD forwarding validation

Layer / File(s) Summary
Leader client URL validation
server/forward.go
Returns Unavailable when no usable leader exists and InvalidArgument when the forwarded host is not advertised by the leader.
Validated delegate forwarding
server/grpc_service.go, server/resource_group_proxy_service.go
Routes forwarding paths through the validated delegate client and reuses the connection within TSO streams. Metadata-provided targets use validation, while PD-discovered leader targets retain the existing delegate path.
Forwarded host rejection coverage
tests/server/tso/tso_proxy_test.go
Verifies follower and unknown forwarded hosts are rejected with InvalidArgument for unary and TSO requests. The unknown-host test also verifies that no connection is accepted.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant grpcService
  participant PDLeader
  participant DelegateClient
  Client->>grpcService: Forward request with pd-forwarded-host
  grpcService->>PDLeader: Validate against advertised client URLs
  PDLeader-->>grpcService: Return leader client URLs
  grpcService->>DelegateClient: Dial or reuse validated connection
  DelegateClient-->>grpcService: Return forwarded response
  grpcService-->>Client: Return response or gRPC status error
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes validation of forwarded PD hosts before dialing.
Description check ✅ Passed The description covers the problem, linked issue, implementation, tests, side effects, related changes, and release note.
Linked Issues check ✅ Passed The changes restrict caller-provided forwarding targets to current leader URLs and reject invalid targets without dialing them, satisfying issue #11070.
Out of Scope Changes check ✅ Passed The code and tests stay within the objective of validating forwarded PD hosts and preventing unauthorized outbound dialing.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ti-chi-bot ti-chi-bot Bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. do-not-merge/needs-triage-completed and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. do-not-merge/needs-linked-issue labels Jul 30, 2026

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
server/forward.go (1)

460-468: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider logging rejected forwarded-host attempts.

Since this is the sole gate preventing a caller from directing PD to dial an arbitrary attacker-supplied pd-forwarded-host, logging rejections (with the offending host) would aid detection of SSRF probing attempts without changing behavior.

📝 Optional logging addition
 	for _, clientURL := range leader.GetClientUrls() {
 		if clientURL == forwardedHost {
 			return s.getDelegateClient(ctx, forwardedHost)
 		}
 	}
+	log.Warn("rejected forwarded host that is not the PD leader's client URL", zap.String("forwarded-host", forwardedHost))
 	return nil, status.Errorf(codes.InvalidArgument, "forwarded host %q is not a client URL of the PD leader", forwardedHost)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/forward.go` around lines 460 - 468, Add logging for rejected
forwarded-host attempts in the visible leader client URL validation flow,
including the offending forwardedHost and enough context to identify the
rejection. Log both the unavailable-leader path and the invalid-host path as
appropriate, while preserving the existing status codes, messages, and return
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@server/forward.go`:
- Around line 460-468: Add logging for rejected forwarded-host attempts in the
visible leader client URL validation flow, including the offending forwardedHost
and enough context to identify the rejection. Log both the unavailable-leader
path and the invalid-host path as appropriate, while preserving the existing
status codes, messages, and return behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ed819c6-bfcc-4f51-8a9c-15481abff0be

📥 Commits

Reviewing files that changed from the base of the PR and between a8ec975 and 79702f8.

📒 Files selected for processing (3)
  • server/forward.go
  • server/grpc_service.go
  • tests/server/tso/tso_proxy_test.go

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 86.36364% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 79.24%. Comparing base (070828c) to head (8985d2b).
⚠️ Report is 4 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #11069      +/-   ##
==========================================
+ Coverage   79.23%   79.24%   +0.01%     
==========================================
  Files         540      541       +1     
  Lines       76010    76520     +510     
==========================================
+ Hits        60226    60638     +412     
- Misses      11533    11589      +56     
- Partials     4251     4293      +42     
Flag Coverage Δ
unittests 79.24% <86.36%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

rleungx added 3 commits July 31, 2026 10:54
Signed-off-by: Ryan Leung <rleungx@gmail.com>
Signed-off-by: Ryan Leung <rleungx@gmail.com>
Signed-off-by: Ryan Leung <rleungx@gmail.com>
@rleungx
rleungx force-pushed the fix-forwarded-host-ssrf-master branch from 79702f8 to 9eb68aa Compare July 31, 2026 02:55

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/server/tso/tso_proxy_test.go`:
- Around line 144-153: Extend TestRejectFollowerForwardedHost to open a Tso
stream using a forward context containing s.follower.GetAddr(), then call Recv
and assert the returned error has codes.InvalidArgument, while preserving the
existing unary GetAllStores assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c29d1463-5ca5-4851-b371-eeb59139fb14

📥 Commits

Reviewing files that changed from the base of the PR and between 79702f8 and 9eb68aa.

📒 Files selected for processing (4)
  • server/forward.go
  • server/grpc_service.go
  • server/resource_group_proxy_service.go
  • tests/server/tso/tso_proxy_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • server/resource_group_proxy_service.go
  • server/forward.go
  • server/grpc_service.go

Comment thread tests/server/tso/tso_proxy_test.go
rleungx added 2 commits July 31, 2026 11:20
Signed-off-by: Ryan Leung <rleungx@gmail.com>
Signed-off-by: Ryan Leung <rleungx@gmail.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/resource_group_proxy_service.go`:
- Line 65: Extract the leader-URL validation from getPDForwardedDelegateClient
into a no-dial helper, then invoke it for forwardedHostFromMetadata targets
before the isLocalRequest branch in the request flow. Reject metadata URLs that
do not belong to the current leader with InvalidArgument, and retain local
handling only after validation succeeds.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9568c497-5d7e-4aa2-a6a7-f29a8101613e

📥 Commits

Reviewing files that changed from the base of the PR and between dd9fc10 and 0a49a48.

📒 Files selected for processing (1)
  • server/resource_group_proxy_service.go

Comment thread server/resource_group_proxy_service.go Outdated
rleungx added 2 commits July 31, 2026 14:41
Signed-off-by: Ryan Leung <rleungx@gmail.com>
Signed-off-by: Ryan Leung <rleungx@gmail.com>
@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/retest

@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-unit-test-next-gen-3

1 similar comment
@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-unit-test-next-gen-3

Signed-off-by: Ryan Leung <rleungx@gmail.com>
@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-unit-test-next-gen-3

@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-unit-test-next-gen-2

@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-unit-test-next-gen-3

@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-unit-test-next-gen-2

@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-integration-realcluster-test

@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-unit-test-next-gen-2

@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/test pull-unit-test-next-gen-3

@ti-chi-bot ti-chi-bot Bot added the needs-cherry-pick-release-8.5 Should cherry pick this PR to release-8.5 branch. label Jul 31, 2026
@rleungx

rleungx commented Jul 31, 2026

Copy link
Copy Markdown
Member Author

/retest

@ti-chi-bot

ti-chi-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: lhy1024

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot Bot added the needs-1-more-lgtm Indicates a PR needs 1 more LGTM. label Jul 31, 2026
@ti-chi-bot

ti-chi-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

[LGTM Timeline notifier]

Timeline:

  • 2026-07-31 10:05:52.883699206 +0000 UTC m=+2176938.919794272: ☑️ agreed by lhy1024.

@ti-chi-bot ti-chi-bot Bot added the approved label Jul 31, 2026
@rleungx
rleungx requested a review from JmPotato July 31, 2026 10:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved dco-signoff: yes Indicates the PR's author has signed the dco. needs-1-more-lgtm Indicates a PR needs 1 more LGTM. needs-cherry-pick-release-8.5 Should cherry pick this PR to release-8.5 branch. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Restrict pd-forwarded-host targets to the current PD leader

2 participants