Composio Shared Connections · Technical case study · October 2026

Composio revoked access. Its proxy kept reading private data and writing to GitHub.

A shared GitHub connection allowed test user B to use an account. We opened a session for B, then removed B from the connection’s access list. Composio denied a new session and the native GitHub tool, yet Proxy Execute in B’s retained session read a private test repository and created a GitHub issue.

Hosted Composio sessionShared connection ACLProvider-confirmed effectsPrivate security advisory
200 / 201private read / issue write

After B was denied, the retained proxy returned a 200 private repository read and a 201 GitHub issue creation. The native tool on that same session returned 403. We confirmed the issues independently at GitHub and repeated the path through a controlled application.

The finding

The access list changed. The retained proxy still used the connection.

A SHARED GitHub connection initially allowed B. We created B’s session, then updated the connection’s access list to explicitly deny B and read it back to confirm the change. The connection remained active.

400New B session pinned to the connection was rejected
403Native GitHub tool in the retained B session was denied
200 / 201Retained proxy read a private repository and created an issue
Action after B was removedObserved result
Create a new B session pinned to the connection400 — B was unauthorized
Use the native GitHub issue tool in B’s retained session403 — B was unauthorized
Read the private repository through Proxy Execute in that sessionGitHub 200; repository marked private
Create a test issue through Proxy Execute in that sessionGitHub 201; issue appeared at the provider

The same access change produced two different answers. Composio denied B at new session creation and native tool execution. Its retained Proxy Execute session continued sending authenticated requests to GitHub. The harmless test issue in our own private repository shows an action at the provider after the access change.

Controlled sequence

We removed B, read the access list back, and tested the next action.

The test used one Composio organization, an owned private GitHub test repository, and composio==0.25.0.

B allowedPin the shared connection and confirm a healthy read.
B removedUpdate the ACL and confirm B’s explicit deny entry.
Proxy readPrivate GitHub repository returns 200.
Proxy writeGitHub creates test issue #5.

The connection owner created the shared connection and allowed B. We pinned it into B’s session and confirmed a private repository read before changing access. At 21:24 UTC on October 9, 2026, we updated the access list to disable access for all users by default, empty the allowed-user list, and put B in the denied-user list. A connection read confirmed those settings.

The retained B session then called session.proxy_execute() for the private repository. GitHub returned 200 and identified the repository as private. A fresh B session could not pin the connection. The native GITHUB_CREATE_AN_ISSUE tool in the retained session returned 403. Proxy Execute in that session created test issue #5 with GitHub 201. A separate signed-in GitHub check found the issue.

Independent effect

The provider read and issue creation were checked at GitHub. The issue was a harmless marker in a repository we owned; its existence establishes a write after the access change.

Execution path

An execution-only key and an application user reproduced the result.

The follow-up tests narrowed the permissions needed by the caller and showed how an app user could reach the retained proxy without receiving the Composio key.

Narrower project credential

Connection management permission was unnecessary.

A second key in the same Composio project had session-management read, session tool-execution write, and Proxy Execute write. It had no connected-account read or write and could not create a session.

Provider confirmed

Access controls

The narrow key could not read the connected account directly. The native GitHub tool in B’s retained session still returned 403.

Retained proxy

It read the private repository with GitHub 200 and created test issue #6 with GitHub 201. GitHub independently confirmed the issue.

B-facing app flow

B triggered the proxy from an app login.

A small local app held the narrow Composio key on its server. B authenticated to the app with an application token, and the server mapped B to the retained session.

Application control

B’s client supplied no Composio key, session ID, connection ID, provider URL, or free-form tool arguments. The app exposed fixed test actions. The shared connection’s access list explicitly denied B before and after the run.

The app’s native GitHub action returned 403. Its Proxy Execute action read the private repository with GitHub 200 and created test issue #7 with GitHub 201. An independent GitHub read confirmed the title, body, and creation time.

What the application run establishes

An app that exposes a proxy action to its user can carry a server-held project key into a retained session after the shared access list removes that user. This was a controlled integration with application authentication supplied by the test harness.

Other paths checked

The bypass followed an already-open session in its owning project.

We tested new sessions, another project, reduced key permissions, changed session restrictions, and an inactive connection.

ControlObserved result
Fresh B session or later attempt to attach the connectionRejected with 400
Separate Composio project and its own keyCould not load the original session or connection
Proxy call without an API keyRejected with 401
Key with session-read permission onlyProxy call rejected with 403
Remove the session’s explicit connection pinProxy read rejected with 400
Restrict the session to zero toolkitsGitHub proxy call rejected with 400
Temporarily make the connection inactiveRetained-session proxy calls rejected with 400

We restored the connection to active after the inactive-account control; B remained explicitly denied. The retained proxy path still worked roughly 20 minutes after the access-list update. Its maximum lifetime was not measured.

The observed path requires an already-open session and a way to execute through it in the same Composio project. The tested calls did not cross a project boundary or expose an OAuth token. The provider evidence covers GitHub in this fixture; other providers were not tested.

Correction to verify

Check today’s access before every proxy request.

Proxy Execute should check the current shared-connection access list against the session’s user before it injects credentials or forwards each request.

Composio could also invalidate affected connection pins as soon as the access list changes. Either approach needs a regression test that opens B’s session while allowed, removes B, and checks that both proxy reads and writes are denied in the retained session.

Repair status

This is a proposed correction. The investigation measured hosted behavior and its controls; it did not test a Composio code change.

Disclosure and evidence

The hosted effect and its controls are in the private report.

We submitted this finding through Composio’s private GitHub Security Advisory process as GHSA-hf4g-q94r-9rv3.

The captured advisory page showed a High label and Triage status. That is the recorded status at the time of capture; its current review state belongs to the private advisory.

The evidence package records the access-list change and readback, request statuses, execution-only key permissions, app client and server receipts, and independent GitHub confirmation of the test issues. This public report omits project credentials, OAuth material, session identifiers, and the private repository’s contents.

Revocation has to reach execution.

B was removed from a shared connection, and Composio enforced that removal at new session creation and native tool execution. A retained Proxy Execute session continued to use the connection for a private read and provider-confirmed writes. Access removal needs to reach the action that actually sends the request.

Primary context

The tested product behavior is documented.

Composio’s documentation describes access lists for shared connections and the session proxy that sends requests with connection credentials. The provider and application receipts were supplied privately with the advisory.

Work with Kronowave

When access changes, what action can the agent still take?

We follow the user, session, connection, and provider effect through the change, then test the controls against the same action.

48-hour Rapid Scan →