# How to Handle Security Boundaries with sly_data in Neuro SAN Studio: A Complete Guide

> Master security boundaries with sly_data in Neuro SAN Studio. Learn to prevent secret leakage by correctly handling to_downstream, from_downstream, and to_upstream data with this complete guide.

- Repository: [Cognizant AI Lab/neuro-san-studio](https://github.com/cognizant-ai-lab/neuro-san-studio)
- Tags: how-to-guide
- Published: 2026-02-27

---

**Neuro SAN Studio enforces a strict security contract around the `sly_data` dictionary to prevent secret leakage, requiring tools to never log its contents, explicitly pass it between upstream and downstream components, and validate required keys fail-fast.**

Neuro SAN Studio uses a mutable Python dictionary called **`sly_data`** to propagate contextual information between chained **CodedTool** instances. Because this dictionary may contain sensitive data like ServiceNow session IDs or API keys, the framework mandates specific security boundaries that govern how data flows from **upstream** tools to **downstream** consumers via `to_downstream` and `from_downstream` patterns.

## Understanding the sly_data Security Contract

The security model for `sly_data` in Neuro SAN Studio rests on four inviolable rules enforced throughout the codebase:

- **Never log `sly_data` contents** – Every tool implementation contains explicit comments warning that `sly_data` may contain secrets. For example, in [`coded_tools/tools/now_agents/nowagent_api_send_message.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/coded_tools/tools/now_agents/nowagent_api_send_message.py) at line 75, the code warns: `# NOTE: sly_data may contain secrets – never log it`.

- **Never log environment variable values** – When copying environment variables into `sly_data`, tools must log only the variable name, never the value. The helper `_get_env_variable` in [`nowagent_api_send_message.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/nowagent_api_send_message.py) (lines 48-55) demonstrates this pattern by logging the lookup attempt while suppressing the actual secret value.

- **Explicit key passing with fail-fast validation** – Downstream tools must receive `sly_data` explicitly and raise `KeyError` immediately if required keys are missing. In [`coded_tools/tools/now_agents/nowagent_api_retrieve_message.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/coded_tools/tools/now_agents/nowagent_api_retrieve_message.py) (lines 70-73), the tool expects `sly_data["session_path"]` and fails fast if absent, preventing silent failures that could mask security issues.

- **Runner-supplied defaults without interpretation** – The CLI runner in [`run.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/run.py) (lines 53-58) can supply a default empty dictionary via `DEFAULT_SLY_DATA` environment variable, but treats this purely as a string fallback without attempting to parse or log secret content.

## Data Flow Between Upstream and Downstream Tools

The `sly_data` dictionary serves as the conduit for **to_downstream** and **from_downstream** communication in multi-tool workflows. **Upstream** tools (like `NowAgentSendMessage`) create or enrich `sly_data`, while **downstream** tools (like `NowAgentRetrieveMessage`) consume these values to locate external resources.

Because Python passes dictionaries by reference, the same mutable object flows through the entire tool chain. This design allows intermediate tools to safely append non-sensitive metadata without exposing existing secret keys to logs or external services.

## Implementing Security Boundaries in Practice

### Propagating Session IDs from Upstream to Downstream

The following pattern demonstrates secure propagation of a session identifier between two tools without logging secrets:

```python

# Upstream tool: NowAgentSendMessage

from coded_tools.tools.now_agents.nowagent_api_send_message import NowAgentSendMessage

send_tool = NowAgentSendMessage()
sly_data = {}  # Empty dict supplied by runner

send_args = {"inquiry": "What is the ticket status?", "agent_id": "abc123"}

# Tool mutates sly_data to add session_path

send_tool.invoke(send_args, sly_data)

# Value exists but must never be logged in production

assert "session_path" in sly_data

```

```python

# Downstream tool: NowAgentRetrieveMessage  

from coded_tools.tools.now_agents.nowagent_api_retrieve_message import NowAgentRetrieveMessage

retrieve_tool = NowAgentRetrieveMessage()
retrieve_args = {"inquiry": "", "agent_id": "abc123"}

# Consumes the session_path added by upstream tool

response = retrieve_tool.invoke(retrieve_args, sly_data)

```

Both tools share the identical `sly_data` object reference, ensuring the session identifier propagates securely without duplication or re-derivation.

### Safely Adding Non-Secret Metadata

When enriching `sly_data` with harmless metadata for downstream consumption, mutate the dictionary directly while avoiding secret exposure:

```python
from datetime import datetime

def enrich_with_timestamp(sly_data: dict) -> None:
    """Add harmless timestamp metadata for downstream tools."""
    sly_data["request_timestamp"] = datetime.utcnow().isoformat()

# Called between upstream and downstream tools

enrich_with_timestamp(sly_data)

```

Downstream tools can now access `sly_data["request_timestamp"]` without risk of secret exposure.

### Preventing Accidental Secret Logging

To maintain security boundaries, implement logging functions that reveal only dictionary structure, never values:

```python
import logging

def safe_log_operation(msg: str, sly_data: dict) -> None:
    """Log operation context without exposing secret values."""
    # Log only key names, never values

    logging.debug("%s - sly_data keys: %s", msg, list(sly_data.keys()))

# Safe usage - logs only that session_path exists, not its value

safe_log_operation("After upstream send", sly_data)

```

## Framework Guard-Rails and Validation

Neuro SAN Studio provides several built-in mechanisms to enforce these security boundaries automatically:

- **Typed CodedTool base class** – Enforces that every `invoke` method signature includes `sly_data: Dict[str, Any]`, ensuring the security context is always available and type-checked.

- **Unit test validation** – The test suite in [`tests/coded_tools/tools/now_agents/unit_tests/test_unit_message_sending_mocked.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/tests/coded_tools/tools/now_agents/unit_tests/test_unit_message_sending_mocked.py) explicitly verifies that `sly_data` mutation is limited to expected keys like `session_path`, preventing unintended side effects. Similarly, [`test_unit_message_retrieval_mocked.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/test_unit_message_retrieval_mocked.py) validates that tools raise exceptions when required `sly_data` keys are missing.

- **Non-secret reference implementations** – Tools like [`coded_tools/tools/visual_question_answering/vqa.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/coded_tools/tools/visual_question_answering/vqa.py) demonstrate safe `sly_data` usage for non-sensitive data (file paths) while maintaining the "never log" comment discipline.

## Summary

- **Never log `sly_data` values** – Log only key names or operation context, never the dictionary contents or environment variable values copied into it.
- **Use explicit pass-by-reference** – The same `sly_data` dict flows from upstream tools (like `NowAgentSendMessage`) to downstream tools (like `NowAgentRetrieveMessage`), preventing secret duplication.
- **Fail fast on missing keys** – Downstream tools must raise `KeyError` immediately when required `sly_data` keys are absent, as implemented in [`nowagent_api_retrieve_message.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/nowagent_api_retrieve_message.py).
- **Leverage runner defaults safely** – The `NeuroSanRunner` in [`run.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/run.py) supplies default empty dictionaries without interpreting content as secrets.
- **Validate with tests** – Unit tests enforce that only expected keys are mutated and that missing session data triggers immediate failures.

## Frequently Asked Questions

### What happens if a downstream tool doesn't receive the required sly_data key?

The downstream tool raises a `KeyError` immediately. For example, `NowAgentRetrieveMessage` in [`coded_tools/tools/now_agents/nowagent_api_retrieve_message.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/coded_tools/tools/now_agents/nowagent_api_retrieve_message.py) attempts to access `sly_data["session_path"]` directly, causing a hard failure if the upstream tool failed to populate the session identifier. This fail-fast behavior prevents tools from operating on stale or invalid security contexts.

### Can I log sly_data for debugging purposes during development?

No. Even during development, you must never interpolate `sly_data` into log messages. The framework's security contract, as documented in [`nowagent_api_send_message.py`](https://github.com/cognizant-ai-lab/neuro-san-studio/blob/main/nowagent_api_send_message.py) and other tools, explicitly prohibits logging because the dictionary may contain production secrets like ServiceNow session IDs or API keys. Instead, log only the keys present using `list(sly_data.keys())`.

### How does sly_data differ from regular tool arguments?

While tool arguments (the first parameter to `invoke`) are typically logged for observability, `sly_data` is explicitly treated as a security boundary container. According to the Neuro SAN Studio source code, `sly_data` bypasses standard logging pipelines and must be passed as a separate dictionary parameter to maintain isolation between operational data and sensitive session state.

### Is sly_data encrypted during transmission between tools?

No, `sly_data` exists only as an in-memory Python dictionary passed by reference between CodedTool instances within the same process. The security boundary relies on process isolation and the "never log" contract rather than encryption, since the data never leaves the runtime memory during normal tool chaining operations.