Skip to content

[bug]: Cross-talk and Identity Leakage in Cron Job Delivery due to Global Environment Variable Usage #10769

@zackzmai

Description

@zackzmai

Bug Description

There is a critical identity leakage issue in the cron job scheduling system. When multiple scheduled tasks are executed, they can "cross-talk," meaning the output of one cron job is delivered to the target (user/channel) of another. This occurs because the system relies on process-global environment variables to track and resolve the delivery target for the current run.

Steps to Reproduce

  1. Configure two different cron jobs (Job A and Job B) with different delivery targets (e.g., User A and User B).
  2. Schedule both jobs to run at the same time or in very close succession.
  3. Trigger the scheduler (e.g., via the gateway's tick() loop).
  4. Observe that the results of Job A are occasionally delivered to User B, or vice versa.

Expected Behavior

Each cron job should operate in a fully isolated identity context. Regardless of how many jobs are running concurrently or sequentially, a job's output must only be delivered to its specifically configured target.

Actual Behavior

Delivery targets are leaked across jobs. The AI Agent may inadvertently send messages to the wrong channel because the tool responsible for delivery reads the target from a global environment variable that may have been overwritten by a different running job.

Affected Component

Agent Core (conversation loop, context compression, memory)

Messaging Platform (if gateway-related)

Telegram

Debug Report

Report       https://paste.rs/22AMA
  agent.log    https://paste.rs/c4KZG
  gateway.log  https://paste.rs/CtCE7

Operating System

Ubuntu 24.04

Python Version

3.11.15

Hermes Version

0.9.0

Additional Logs / Traceback (optional)

The leakage follows this execution path:
1. cron/scheduler.py → run_job(): Sets global identity via os.environ["HERMES_CRON_AUTO_DELIVER_CHAT_ID"] = ...
2. model_tools.py → handle_function_call(): Dispatches tool calls but fails to pass the session_id or identity context to the tool handler.
3. tools/send_message_tool.py → _get_cron_auto_delivery_target(): Resolves the target using os.getenv("HERMES_CRON_AUTO_DELIVER_CHAT_ID").
4. If Job B has started and overwritten the environment variable while Job A is still executing its tool calls, Job A will deliver its result to Job B's target.

Root Cause Analysis (optional)

The root cause is the use of Process-Global State (os.environ) to store Session-Specific Metadata.

  • In cron/scheduler.py, identity is injected into the global environment.
  • In model_tools.py, the dispatch mechanism creates a "context gap" by not forwarding session identity to the tool handlers.
  • In tools/send_message_tool.py, the tool blindly trusts the global environment to determine the recipient.
    This architecture is fundamentally incompatible with any form of concurrency or rapid sequential execution, as os.environ is shared across all threads in the process.

Proposed Fix (optional)

  1. Eliminate Global Env Vars: Remove all os.environ injections of session/delivery metadata in cron/scheduler.py.
  2. Pass Identity Explicitly:
    • Store the delivery target within the AIAgent instance or a session-scoped context object.
    • Update model_tools.py to pass the session_id and associated identity metadata into the registry.dispatch call.
  3. Update Tool Resolution: Modify send_message_tool.py to retrieve the delivery target from the provided session context instead of calling os.getenv().

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/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