Skip to content

Harden plugin connection tests and outbound action requests - #1925

Open
Paul Lizer (paullizer) wants to merge 3 commits into
Developmentfrom
paullizer-plugin-ssrf-hardening
Open

Paul Lizer (paullizer) wants to merge 3 commits into
Developmentfrom
paullizer-plugin-ssrf-hardening

Conversation

@paullizer

@paullizer Paul Lizer (paullizer) commented Nov 11, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Authenticated action tests and runtime clients need to validate where connections actually go, not just the supplied URL or the caller's login. Add shared connection-bound HTTP/MCP guards against forbidden destinations, DNS rebinding, unsafe redirects, authority overrides, and ambient server credentials.
  • Require the corresponding authoring/type permissions before connection tests or discovery. Retained credentials cannot silently follow a changed connector/origin, and supplied Key Vault references must match the selected stored action field.
  • Preserve reachable enterprise private FQDNs/IPs, normal shared-action execution, and Yamcs reverse-proxy authentication, identity sources, TLS options, and unchanged-origin credential rotation. No new administrator destination allowlist or blanket action-credential reset.
  • Integrate guarded clients with OpenAPI, RocksDB, Yamcs, Tableau, Smart HTTP, Databricks and native MCP transports; remove the unguarded HTTP fallback. Add offline SDK/compatibility regressions, renew Cosmos reviews, and document upgrade impact. The Development agent-credential authorization changes are preserved in the merge resolution; v0.261.436 includes the focused CodeQL test-fixture follow-up.

Upgrade considerations: Loopback, link-local and cloud infrastructure action targets are now refused, including DNS aliases. Cross-origin redirects require configuring the final service URL. Deployment-wide HTTP(S) forward-proxy routing is explicitly refused by the guarded clients rather than silently bypassed. Yamcs's existing reverse-proxy authentication is different and remains supported; a remote proxy may still use localhost for its own upstream. Unchanged ordinary public/private actions do not require a mandatory re-save or action-credential reset. The independent agent-credential upgrade rules already present in Development still apply.

Linked issue

N/A. No issue was created, as requested.

Release Notes & Latest Features

  • New Feature
  • Bug Fix
  • UI Enhancement
  • Breaking Change
  • Internal only

Is this visible to end users?

  • Yes
  • No

Is this admin-facing (Admin Settings, governance, deployment, config)?

  • Yes
  • No

Should this become a Latest Feature card?

  • Yes
  • No
  • Already added

Screenshot needed for the card?

  • Yes
  • No
  • Attached

Version bump

  • application/single_app/config.py VERSION third segment bumped, or not needed because this is docs-only
  • deployers/version.txt bumped, or not needed because deployers/ was not changed

Application version in this PR: 0.261.436. The merged guard implementation is recorded in 0.261.435; the CodeQL test-fixture follow-up increments the patch segment to 0.261.436. Conflict resolution preserved both action destination protection and agent credential authorization. No deployer changes.

Testing / validation

All service I/O was mocked or network-blocked; no production, on-premises or metadata endpoint was probed. Initial transport validation included pinned aiohttp 3.14.4 in an isolated dependency overlay. No deployment was performed.

PowerShell test setup: $env:PYTHONPATH = "$((Get-Location).Path)\application\single_app;$((Get-Location).Path)\functional_tests".

CodeQL follow-up verification on 4fbd88796:

  • python -m pytest -q --tb=short --disable-warnings --maxfail=4 -p no:cacheprovider -p test_support.cosmos_network_guard .\functional_tests\test_outbound_destination_policy.py .\functional_tests\test_plugin_outbound_destination_security.py - 83 passed. Exact parsed-origin checks replace the flagged URL substring assertions; the WebSocket expected-error and single-connection assertions remain intact.
  • python -m pytest -q --tb=short --disable-warnings --maxfail=4 -p no:cacheprovider -p test_support.cosmos_network_guard .\functional_tests\test_yamcs_basic_auth.py .\functional_tests\test_yamcs_action_plugin.py - 28 passed. Credential fixtures initialize their inherited fields while preserving API-key and Basic authentication behavior.
  • python .\scripts\check_cosmos_response_boundaries.py - 1104 owners, 430 doubles, 0 review gaps; no inventory changes required.
  • python .\functional_tests\test_docs_app_surface_coverage.py - 7/7 passed.
  • python .\functional_tests\test_docs_site_quality.py - 6/6 passed.
  • git --no-pager -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol diff HEAD^ HEAD --check - passed.

Post-merge verification on 9c108d22a:

  • python -m pytest -q --tb=short --disable-warnings --maxfail=4 -p no:cacheprovider -p test_support.cosmos_network_guard .\functional_tests\test_outbound_destination_policy.py .\functional_tests\test_plugin_outbound_destination_security.py .\functional_tests\test_workspace_authoring_sdk_boundaries.py .\functional_tests\test_shared_agent_secret_responses.py .\functional_tests\test_mcp_action_route_security.py - 162 passed. Covers actual connection selection, DNS/redirect checks, TLS/Host preservation, field-bound credential reuse, installed SDK integration and the combined agent/action contracts.
  • python -m pytest -q --tb=short --disable-warnings --maxfail=4 -p no:cacheprovider -p test_support.cosmos_network_guard .\functional_tests\test_workspace_authoring_backend.py .\functional_tests\test_shared_action_secret_responses.py .\functional_tests\test_agent_credential_reentry.py .\functional_tests\test_agent_credential_security.py - 215 passed.
  • python .\scripts\check_cosmos_response_boundaries.py --run-contracts - 1603 passed, no filtering or deselection; 1104 owners, 430 doubles, 0 review gaps. Shared-module producer bodies/call shapes were compared with Development before renewing their combined-source reviews. SDK-default bootstrap evidence runs legacy standalone test modules in network-blocked subprocesses so their import stubs cannot contaminate other suites.
  • python .\functional_tests\test_docs_app_surface_coverage.py - 7/7 passed; inventory is current and the internal MCP transport is not exposed as a new action.
  • python .\functional_tests\test_docs_site_quality.py - 6/6 passed.
  • git --no-pager -c core.whitespace=blank-at-eol,blank-at-eof,space-before-tab,cr-at-eol diff --cached --check - passed before the merge commit.

Earlier implementation verification:

  • python -m pytest -q --tb=short --disable-warnings --maxfail=4 -p no:cacheprovider -p test_support.cosmos_network_guard .\functional_tests\test_yamcs_basic_auth.py .\functional_tests\test_yamcs_action_plugin.py .\functional_tests\test_rocksdb_plugin.py .\functional_tests\test_tableau_action_plugin.py .\functional_tests\test_plugin_error_response_sanitization.py - 45 passed.
  • python .\functional_tests\route_tests\test_route_blueprint_policy_inventory.py - 15/15 passed.
  • python .\functional_tests\route_tests\test_route_unauthenticated_policy_contract.py - 10/10 passed.
  • python .\functional_tests\route_tests\test_route_policy_test_coverage.py - 4/4 passed.

Documentation

  • Release notes updated, or not needed
  • Feature documentation updated, or not needed
  • Fix documentation updated, or not needed

Updated the workspace guide, governance reference, and affected action references with a private/public/proxy compatibility matrix and migration considerations. Added docs/explanation/fixes/PLUGIN_OUTBOUND_DESTINATION_GUARD_FIX.md, which records implementation in v0.261.435 and the test-fixture follow-up in v0.261.436. No new user-facing capability or Latest Feature card is introduced. Release-note approval was requested but unavailable, so the optional release notes remain unchanged.

Security checklist

  • New Flask routes include @swagger_route(security=get_auth_security())
  • Settings sent to non-admin frontends use sanitize_settings_for_user()
  • Browser JavaScript is served from local SimpleChat static assets only; no CDN-hosted JS
  • No secrets, keys, connection strings, or local-only artifacts are included

No new routes, settings-bearing frontend payloads, or browser assets in the PR's changes. Existing route decorators and Blueprint policies remain intact; test credentials are synthetic.

Enforce connection-bound HTTP and MCP destination safety while preserving enterprise private endpoints and Yamcs reverse-proxy authentication. Require test authoring permissions and original-field credential context, prevent implicit credential retargeting, and update compatibility docs and offline SDK regressions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Combine the merged agent credential authorization work with action destination and credential-retention protections. Renew shared-module Cosmos reviews and align the application patch version and related documentation at 0.261.435.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Compare parsed SDK request origins exactly, initialize inherited credential fixtures, and remove unused test code while preserving the DNS guard assertions. Bump the application patch version to 0.261.436.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
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