Skip to content

0.9.12a1: router split removes the "router" key from state.dict(), so reflex-enterprise 0.9.5's REST session-token redaction silently no-ops (client_token/session_id returned over HTTP) #7214

Description

@masenf

Describe the bug

#7068 split State.router into five per-field vars (rx_router_url, rx_router_page, rx_router_session, rx_router_headers, rx_router_route_id) and made router a property with no backing field, so it no longer appears in state.dict() or in deltas. Downstream code that looked up the router key now finds nothing. reflex-enterprise 0.9.5's redact_router_session() (reflex_enterprise/plugins/event_handler_api.py:733) is exactly such code: it blanks router.session.client_token / session_id before state is returned over the REST, MCP and agent-delta surfaces. On 0.9.12a1 the redaction silently does nothing, and POST /_reflex/retrieve_state plus the ndjson event deltas of /_reflex/event/<state>/<handler> return the server-side rx_router_session.client_token and session_id — identifiers the caller never presented (not its bearer). On 0.9.11.post1 the same responses carry router with client_token blanked.

Today this is masked by #7211 (reflex-enterprise 0.9.5 apps cannot start on 0.9.12a1 at all); it becomes live the moment #7211 is fixed in reflex against the already-published reflex-enterprise 0.9.5, which pins reflex[db]>=0.9.6 with no upper bound. No released stable combination is affected today.

To Reproduce

In a venv with reflex 0.9.12a1 + reflex-enterprise 0.9.5 (plus a test-only shim for #7211 so the module imports), from a neutral cwd:

import reflex as rx
from reflex.istate.data import RouterData
from reflex.state import State
from reflex_enterprise.plugins.event_handler_api import redact_router_session, router_data_for_token

st = State(_reflex_internal_init=True)
st.router_data = dict(router_data_for_token("SECRET-CLIENT-TOKEN", headers={"host": "x"}, query={"a": "1"}, path="/tickets"))
st.router = RouterData.from_router_data(st.router_data)
d = redact_router_session(st.dict())
print(sorted(d[State.get_full_name()]))
# 0.9.12a1: is_hydrated + the five rx_router_* keys, no 'router'; searching d for "SECRET-CLIENT-TOKEN"
#           finds it under rx_router_session.client_token.
# 0.9.11.post1: 'router' present with client_token blanked; the secret appears nowhere.

Over HTTP: the unmodified tickets demo (with the #7211 shim) on 0.9.12a1, an anonymous app bearer, POST /_reflex/retrieve_state and POST /_reflex/event/<state>/seed — both bodies contain the real rx_router_session.client_token; blanked on 0.9.11.post1.

Expected behavior

Session identifiers are never returned over the REST surface, whatever reflex version reflex-enterprise runs on.

Where the fix belongs / what 0.9.12 needs

  • reflex-enterprise: redact the rx_router_session entry (and keep redacting router for reflex < 0.9.12), released in lockstep with 0.9.12, ideally with a reflex>=0.9.12 lower bound in the version that carries it.
  • reflex: a changelog / breaking-change note that router is no longer a key in state.dict() or in deltas and that downstream code keyed on it must switch to the rx_router_* entries (there is no such note today). Whether reflex should additionally offer a redaction hook, or refuse to run with a known-incompatible reflex-enterprise, is a maintainer decision.

Specifics (please complete the following information):

  • Python Version: 3.11.15
  • Reflex Version: 0.9.12a1 / reflex-base 0.9.12a1 (regression vs 0.9.11.post1); reflex-enterprise 0.9.5
  • OS: Linux (Ubuntu 24.04 container)

Additional context

0.9.12a1 pre-release QA campaign FINDING-011, confirmed over HTTP by an adversarial verifier. Evidence and scripts: prerelease-testing/2026-09-18-v0.9.12a1/ent_map_dnd_flow_mantine/ (scripts/probe_router_redact.py, verification/v_leak_http.py, NOTES.md) and FINDINGS.md in the parent directory.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions