Skip to content

Add client.allowedOrigins config option#13829

Merged
lukasmasuch merged 4 commits intodevelopfrom
lukasmasuch/allowed-origins
Feb 6, 2026
Merged

Add client.allowedOrigins config option#13829
lukasmasuch merged 4 commits intodevelopfrom
lukasmasuch/allowed-origins

Conversation

@lukasmasuch
Copy link
Copy Markdown
Collaborator

@lukasmasuch lukasmasuch commented Feb 5, 2026

Describe your changes

Implement a new client.allowedOrigins configuration option to allow deployers to customize which origins can send cross-origin postMessage commands to embedded Streamlit apps. The default list of Community Cloud origins is now configurable via config.toml instead of being hardcoded.

Github Issues

Testing Plan

  • All existing unit tests pass (127 tests)
  • Configuration option is properly validated and accessible via config.get_option()
  • Both Tornado and Starlette server implementations use the config option

Contribution License Agreement

By submitting this pull request you agree that all contributions to this project are made under the Apache 2.0 license.

Cursor Bugbot reviewed your changes and found no issues for commit f20b7b5

Implement a new configuration option to allow deployers to customize which
origins can send cross-origin postMessage commands to embedded Streamlit apps.
Moves the default allowed origins list from hardcoded constants in routes.py
to the config system, making it configurable via config.toml.
Copilot AI review requested due to automatic review settings February 5, 2026 00:28
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 5, 2026

✅ PR preview is ready!

Name Link
📦 Wheel file https://core-previews.s3-us-west-2.amazonaws.com/pr-13829/streamlit-1.53.1-py3-none-any.whl
📦 @streamlit/component-v2-lib Download from artifacts
🕹️ Preview app pr-13829.streamlit.app (☁️ Deploy here if not accessible)

@snyk-io
Copy link
Copy Markdown
Contributor

snyk-io bot commented Feb 5, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@lukasmasuch lukasmasuch changed the title Add client.allowedOrigins config option Add client.allowedOrigins config option Feb 5, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a new client.allowedOrigins configuration option that allows deployers to customize which origins can send cross-origin postMessage commands to embedded Streamlit apps. Previously, the list of allowed Community Cloud origins was hardcoded in routes.py.

Changes:

  • Moved _DEFAULT_ALLOWED_MESSAGE_ORIGINS constant from routes.py to config.py
  • Added new client.allowedOrigins config option with multiple=True to accept a list of origin strings
  • Updated both Tornado (routes.py) and Starlette (starlette_routes.py) server implementations to use config.get_option("client.allowedOrigins") instead of the hardcoded constant
  • Updated test imports and added the new config key to the test that validates all config option keys
  • Added unrelated ty: ignore[unresolved-attribute] type checker suppression comments to existing test code

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
lib/streamlit/config.py Defines _DEFAULT_ALLOWED_MESSAGE_ORIGINS constant and creates new client.allowedOrigins config option with proper description and default value
lib/streamlit/web/server/routes.py Removes hardcoded constant and updates HostConfigHandler to use config option
lib/streamlit/web/server/starlette/starlette_routes.py Updates _host_config_endpoint to use config option instead of importing constant
lib/tests/streamlit/web/server/routes_test.py Updates import to reference constant from config module instead of routes
lib/tests/streamlit/config_test.py Adds new config key to validation test and adds type checker suppression comments to unrelated test code

@lukasmasuch lukasmasuch added security-assessment-completed change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users ai-review If applied to PR or issue will run AI review workflow labels Feb 5, 2026
@github-actions github-actions bot removed the ai-review If applied to PR or issue will run AI review workflow label Feb 5, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 5, 2026

Summary

This PR introduces a new client.allowedOrigins configuration option that allows deployers to customize which origins can send cross-origin postMessage commands to embedded Streamlit apps. The change moves the previously hardcoded list of Community Cloud domains from routes.py to a configurable option in config.py, making the allowed origins customizable via config.toml.

Key changes:

  • Added new client.allowedOrigins config option with visibility="hidden" and multiple=True
  • Moved _DEFAULT_ALLOWED_MESSAGE_ORIGINS from routes.py to config.py
  • Updated both Tornado (routes.py) and Starlette (starlette_routes.py) server implementations to use the config option
  • Updated test imports accordingly

Code Quality

The code quality is good and follows existing patterns in the codebase:

  1. Config option definition (`lib/streamlit/config.py:655-673): The option is correctly defined with:

    • visibility="hidden" - appropriate for an advanced option
    • multiple=True - correct for a list-type config
    • Clear description with security guidance
    • Default value maintains backwards compatibility
  2. Server implementations (lib/streamlit/web/server/routes.py:231-233 and lib/streamlit/web/server/starlette/starlette_routes.py:385): Both correctly convert the config value to a list, which is necessary since multiple=True config options return tuples.

  3. Type annotations: Correctly added list[str] type hints in both server files.

  4. Unrelated fixes (lib/tests/streamlit/config_test.py): The # ty: ignore[unresolved-attribute] comments appear to be unrelated type checker fixes, which is acceptable as cleanup.

Test Coverage

Existing tests are updated correctly:

  • Import path for _DEFAULT_ALLOWED_MESSAGE_ORIGINS updated in routes_test.py
  • New config key added to the config options test list

Test coverage gap identified:

There is no test that verifies the client.allowedOrigins config option can be overridden with custom values. The existing tests only verify:

  • Default values are returned when developmentMode=False (routes_test.py:313-329)
  • http://localhost is added when developmentMode=True (routes_test.py:331-337)
  • Similar tests exist for Starlette (starlette_app_test.py:631-676)

However, there is no test that sets a custom client.allowedOrigins configuration value and verifies it appears in the host-config endpoint response. This is an important test case to ensure the feature works as intended.

For comparison, similar config options like server.corsAllowedOrigins have tests that verify custom values work (see server_util_test.py:34-52).

Backwards Compatibility

The change is fully backwards compatible:

  • The default value is the same list that was previously hardcoded
  • The visibility="hidden" ensures the option doesn't clutter the output of streamlit config show
  • No changes to the host-config endpoint response structure

Security & Risk

Security considerations are appropriately addressed:

  1. The description includes a security note recommending that for untrusted app code, deployers should override the /_stcore/host-config endpoint directly rather than relying on this config option.

  2. The feature allows both restricting origins (more secure) and expanding origins (potential risk if misconfigured), which is expected for a customizable allow-list.

  3. Low risk: The default behavior is unchanged, so existing deployments are unaffected.

Accessibility

No frontend changes in this PR - accessibility considerations are not applicable.

Recommendations

  1. Add a test for custom config values: Add a test case that verifies custom client.allowedOrigins values are correctly returned by the host-config endpoint. Example test to add in routes_test.py:
@patch_config_options({
    "global.developmentMode": False,
    "client.allowedOrigins": ["https://custom.example.com", "https://another.example.com"]
})
def test_custom_allowed_message_origins(self):
    """Test that custom client.allowedOrigins values are used."""
    response = self.fetch("/_stcore/host-config")
    response_body = json.loads(response.body)
    assert response.code == 200
    assert response_body["allowedOrigins"] == [
        "https://custom.example.com",
        "https://another.example.com"
    ]
    # Verify defaults are NOT included when custom values are set
    assert "https://*.streamlit.app" not in response_body["allowedOrigins"]

A similar test should be added for the Starlette implementation in starlette_app_test.py.

  1. Consider adding an empty list test: Verify behavior when client.allowedOrigins is set to an empty list [], to ensure the feature handles edge cases correctly.

Verdict

CHANGES REQUESTED: The implementation is clean and backwards compatible, but the PR should include unit tests that verify custom client.allowedOrigins configuration values are correctly applied to the host-config endpoint response, ensuring the feature works as intended.


This is an automated AI review using opus-4.5-thinking. Please verify the feedback and use your judgment.

@github-actions github-actions bot added the do-not-merge PR is blocked from merging label Feb 5, 2026
- Add unit tests for custom client.allowedOrigins config values in both
  Tornado and Starlette implementations
- Add tests for empty allowedOrigins list edge case
- Fix make check to run ty without explicit files so it respects the
  include/exclude config in pyproject.toml
@lukasmasuch lukasmasuch added ai-review If applied to PR or issue will run AI review workflow and removed do-not-merge PR is blocked from merging labels Feb 5, 2026
@github-actions github-actions bot removed the ai-review If applied to PR or issue will run AI review workflow label Feb 5, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 5, 2026

Summary

This PR introduces a new client.allowedOrigins configuration option that allows deployers to customize which origins can send cross-origin postMessage commands to embedded Streamlit apps. The change moves the hardcoded list of Community Cloud origins from routes.py to config.py and makes it configurable via config.toml. Both Tornado and Starlette server implementations are updated to read from this config option.

Key changes:

  • Added _DEFAULT_ALLOWED_MESSAGE_ORIGINS and client.allowedOrigins config option in lib/streamlit/config.py
  • Updated HostConfigHandler (Tornado) and _host_config_endpoint (Starlette) to use the config option
  • Added unit tests for both server implementations covering custom and empty origins scenarios

Code Quality

The implementation follows existing patterns well:

  1. Config option design (lib/streamlit/config.py:655-673): Uses appropriate parameters - visibility="hidden" for an advanced option, multiple=True for list support, and sensible defaults preserving backward compatibility.

  2. Defensive copying: Both implementations correctly create a copy of the list before potentially modifying it (routes.py:231-233 and starlette_routes.py:385), preventing mutation of the config value.

  3. Type annotations: Proper type hints are used (list[str]).

Minor observations:

  • Makefile change (line 541): The change from uv run ty check $$PY_FILES to uv run ty check appears unrelated to the PR's main purpose. This should be documented in the PR description or split into a separate commit for clarity.

  • Type ignore comments in config_test.py: The # ty: ignore[unresolved-attribute] additions appear to be fixing type checker issues on existing code, unrelated to the main feature. This cleanup is fine but could be mentioned in the PR.

Test Coverage

Strengths:

  • Tests cover both Tornado (routes_test.py:339-371) and Starlette (starlette_app_test.py:679-742) implementations
  • Positive assertions verify custom values are used correctly
  • Negative assertions verify defaults are NOT included when custom values are set (good anti-regression check)
  • Empty array case is tested to ensure it produces an empty list

Missing test case:

There's no test for the combined scenario of developmentMode=True with custom allowedOrigins. The current tests verify:

  • ✅ Dev mode ON + default origins → localhost is appended
  • ✅ Dev mode OFF + custom origins → custom values used
  • ✅ Dev mode OFF + empty origins → empty list returned
  • ❌ Dev mode ON + custom origins → localhost should be appended to custom list

Recommendation: Add a test like:

@patch_config_options(
    {
        "global.developmentMode": True,
        "client.allowedOrigins": [
            "https://custom.example.com",
        ],
    }
)
def test_custom_allowed_message_origins_with_dev_mode(self):
    """Test that localhost is appended to custom origins in dev mode."""
    response = self.fetch("/_stcore/host-config")
    response_body = json.loads(response.body)
    assert response.code == 200
    assert "https://custom.example.com" in response_body["allowedOrigins"]
    assert "http://localhost" in response_body["allowedOrigins"]

Backwards Compatibility

No breaking changes. The default value preserves the exact same list of origins that was previously hardcoded. Existing apps and deployments will continue to work without any configuration changes.

The config option is hidden (visibility="hidden"), so it won't appear in generated documentation or streamlit config show, reducing the risk of accidental misconfiguration.

Security & Risk

Security considerations:

  1. Positive: The implementation allows operators to restrict origins to a smaller, more specific list, improving security posture for deployments that don't need Community Cloud origins.

  2. Positive: The description includes a helpful security note advising that for untrusted app code, it's safer to override the /_stcore/host-config endpoint directly.

  3. Low risk concern: Users could misconfigure origins and inadvertently break embedding functionality. However, since the option is hidden, this is mitigated.

No security vulnerabilities identified. The change is an additive configuration option that maintains the same default security posture.

Accessibility

No frontend changes in this PR - this is a backend-only configuration option. No accessibility concerns apply.

Recommendations

  1. Add missing test case: Add a test for developmentMode=True combined with custom allowedOrigins to verify localhost is still appended to custom origins.

  2. Consider documenting the Makefile change: The ty check change should either be documented in the PR description or split into a separate commit, as it appears unrelated to the main feature.

  3. (Optional) Consider adding a brief note in the PR description about why the # ty: ignore comments were added to config_test.py.

Verdict

APPROVED: This is a well-implemented, backwards-compatible configuration option with good test coverage. The missing test case for dev mode + custom origins is a minor gap that would be nice to address but is not blocking. The implementation follows existing patterns, maintains security defaults, and enables deployers to customize allowed origins for their specific needs.


This is an automated AI review using opus-4.5-thinking. Please verify the feedback and use your judgment.

- Add test verifying localhost is appended to custom allowedOrigins
  when developmentMode=True (both Tornado and Starlette)
- Remove ty: ignore comments from config_test.py since ty no longer
  checks test files after Makefile change
Copy link
Copy Markdown
Collaborator

@sfc-gh-bnisco sfc-gh-bnisco left a comment

Choose a reason for hiding this comment

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

Discussed tradeoffs offline 👍

Explain that this config option is not tamper-proof since app code can
modify the configuration, and recommend overriding the host-config
endpoint at the platform/proxy level for untrusted code scenarios.
@lukasmasuch lukasmasuch enabled auto-merge (squash) February 6, 2026 19:07
@lukasmasuch lukasmasuch merged commit be31347 into develop Feb 6, 2026
42 checks passed
@lukasmasuch lukasmasuch deleted the lukasmasuch/allowed-origins branch February 6, 2026 19:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:feature PR contains new feature or enhancement implementation impact:users PR changes affect end users

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make "allowed message origins" a config option instead of hard-coded list

3 participants