Skip to content

Bug: Multi-User Session Hijacking & Global State Collision in LinkedIn Agent #130

@SunkariManwithaGopal

Description

@SunkariManwithaGopal

Summary

In Composio/linkedln/agent.py, the LinkedInAgent instance is declared as a single global variable (linkedin_agent). The message handler handle_message dynamically overwrites this global instance's user_id and manages authentication flow states (connection_request, connected_account, etc.) globally across all users.

Severity
High / Critical

Type
Broken Object Level Authorization (BOLA) / Session Hijacking / Shared State Concurrency Vulnerability

Affected Path
Composio/linkedln/agent.py

Affected Functions
Global instantiation of linkedin_agent (~lines 440–443)
handle_message protocol handler (~lines 462–517)
LinkedInAgent.initiate_auth() (~lines 45–56)
LinkedInAgent.complete_auth() (~lines 58–70)
LinkedInAgent.process_query() (~lines 108–143)
Vulnerable Logic
python

Initialize LinkedInAgent

linkedin_agent = LinkedInAgent(
    user_id="",
    auth_config_id=os.getenv("LINKEDIN_AUTH_CONFIG_ID")
)

...

@protocol.on_message(ChatMessage)

async def handle_message(ctx: Context, sender: str, msg: ChatMessage):
    # ...
            # Check if authentication request
            if "connect" in text.lower() or "authenticate" in text.lower():
                user_id = extract_user_id_from_query(text)
                if user_id:
                    linkedin_agent.user_id = user_id
                    print(f"🔐 Setting user ID to: {user_id}")
                    result = linkedin_agent.process_query(text)

Root Cause
The uAgents framework processes incoming messages asynchronously from multiple distinct sender addresses. Because the LinkedIn agent stores user-specific parameters (user_id, connection_request, connected_account) as mutable attributes on a single shared global linkedin_agent object, concurrent users will overwrite each other's session configuration.

Security Impact
An attacker can hijack another user's LinkedIn session or complete the authentication flow on behalf of another user.

If User A initiates authentication, their redirect URL and connection state are stored in the global instance.
If User B triggers a message before User A finishes, they overwrite the user_id and can intercept the authenticated account or execute API commands against User A's account once complete.
This represents a severe trust-boundary breach allowing unauthorized LinkedIn profile updates and posts

Steps to reproduce

1.Prerequisites
git clone https://github.com/fetchai/innovation-lab-examples.git
cd innovation-lab-examples/Composio/linkedln
pip install -r requirements.txt

Set up LINKEDIN_AUTH_CONFIG_ID and OPENAI_API_KEY in .env.
2.Start Agent
python agent.py

3.Simulate Concurrent Requests

  • User A sends: "connect to LinkedIn userA"

    • Global linkedin_agent.user_id is set to "userA".
    • connection_request is initiated.
  • User B sends: "connect to LinkedIn userB"

    • Global linkedin_agent.user_id is overwritten to "userB".
  • User A sends: "Auth complete" or any action.

    • The agent checks authentication status for "userB" instead of "userA", leading to cross-user state corruption or session hijacking.

Expected behavior

The agent must keep distinct session state and configuration isolated per user/sender address.

Actual behavior

All message handlers access the same global linkedin_agent instance, leading to state collisions.

Affected file or folder path

Composio/linkedln/agent.py

Logs / traceback

Traceback (most recent call last):
  File ".../linkedln/agent.py", line 462, in handle_message
    linkedin_agent.user_id = message["user_id"]
AttributeError: 'LinkedInAgent' object has no attribute 'user_id'
(Additional logs showing interleaved requests from two users were omitted for brevity.)

Environment

-OS: Windows 11 (64‑bit) - Python: 3.10.12 - pip packages: fastapi==0.109.0, uvicorn==0.24.0, composio-sdk==0.3.1 - Environment variables: LINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRET

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions