# How Agent Reach Securely Stores and Retrieves Credentials: A Complete Technical Guide

> Agent Reach securely stores credentials in an encrypted config yaml file using strict permissions. Learn how this system retrieves values and allows environment variable overrides.

- Repository: [Pnant/Agent-Reach](https://github.com/Panniantong/Agent-Reach)
- Tags: deep-dive
- Published: 2026-07-14

---

**Agent Reach stores credentials in a YAML file at `~/.agent-reach/config.yaml` with strict 600 file permissions and a 700 directory, retrieving values from this encrypted-at-rest location while allowing environment variable overrides.**

Agent Reach, an open-source framework maintained in the **Panniantong/Agent-Reach** repository, implements a defense-in-depth approach to secret management. The configuration system ensures that API keys, tokens, and other sensitive data remain accessible to the user while protected from unauthorized access through filesystem permissions and secure I/O operations.

## Private Configuration Directory Creation

When instantiating a `Config` object, Agent Reach immediately establishes a secure workspace. The `__init__` method calls `_ensure_dir()`, which delegates to `make_private_dir()` in **agent_reach/utils/paths.py** to create the `~/.agent-reach` directory.

This utility applies **700 permissions** (read, write, and execute for the owner only) using `os.mkdir()` with a restrictive mode. According to the source code at lines 10-16, this prevents other users on the system from listing or accessing the configuration folder, establishing the first layer of the security boundary.

## Atomic File Creation with Restrictive Permissions

The `save()` method in **agent_reach/config.py** (lines 55-73) implements platform-specific secure writing to prevent race conditions where credentials might be temporarily world-readable.

On supported platforms, the code uses `os.open()` with flags that atomically create the file with **600 permissions** (read/write for owner only). If the platform does not support these flags, Agent Reach falls back to a standard `open()` call followed immediately by `chmod 0o600`. This eliminates the window between file creation and permission restriction where secrets could be exposed.

## Loading and Retrieving Credentials

The `load()` method (lines 44-49) reads the YAML configuration using `yaml.safe_load()`, initializing an empty dictionary if the file does not yet exist. 

When retrieving values via `get()` (lines 75-84), Agent Reach implements a hierarchical lookup strategy:

1. First, check the in-memory dictionary for the key
2. If not found, check for an environment variable with the same name in **uppercase**

This design allows users to override persistent credentials with temporary environment variables, supporting CI/CD pipelines and shared development environments without writing secrets to disk.

## Persisting New Secrets Safely

The `set(key, value)` method (lines 86-90) ensures that updates are immediately committed to disk. When you store a new API key or token, the method updates the in-memory dictionary and invokes `save()`, writing the file with the same strict 600 permissions used during initial creation.

This immediate persistence prevents data loss while maintaining the security posture, ensuring that even freshly added credentials receive the same filesystem protection as existing entries.

## Masking Secrets in Output and Logs

To prevent accidental exposure in logs, stack traces, or CLI output, the `to_dict()` method (lines 108-128) implements automatic masking. Any configuration key containing sensitive keywords—such as "key", "token", or "secret"—has its value truncated to the first eight characters followed by `...`.

For example, an OpenAI API key appears as `sk-xxxxx...` rather than the full string, protecting against shoulder surfing or accidental copy-paste into support tickets.

## Practical Implementation Example

```python
from agent_reach.config import Config

# Initialize (creates ~/.agent-reach with 700 permissions if needed)

cfg = Config()

# Store a secret - saved with 0o600 permissions atomically

cfg.set("openai_api_key", "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx")

# Retrieve (checks config.yaml first, then OPENAI_API_KEY env var)

api_key = cfg.get("openai_api_key")

# Display safely (automatically masked in output)

print("Config:", cfg.to_dict())  # Shows: {'openai_api_key': 'sk-xxxxx...'}

```

## Summary

- **Agent Reach** stores credentials in `~/.agent-reach/config.yaml` with owner-only permissions
- The **configuration directory** is created with `700` permissions via `make_private_dir()` in **agent_reach/utils/paths.py**
- The **save()** method uses `os.open()` with atomic `600` permission flags or falls back to immediate `chmod 0o600`
- **Retrieval** prioritizes the YAML file but allows **environment variable overrides** via the `get()` method
- **Masking logic** in `to_dict()` prevents secret leakage in logs by truncating sensitive values

## Frequently Asked Questions

### Where does Agent Reach store configuration files?

Agent Reach persists all user-specific settings to `~/.agent-reach/config.yaml` in the user's home directory. This location is determined at runtime and created automatically with private permissions when the `Config` class is first instantiated.

### What file permissions does Agent Reach use for credentials?

The framework applies the principle of least privilege: the directory receives **700** permissions (owner read/write/execute only), while the configuration file itself receives **600** permissions (owner read/write only). These restrictions are enforced atomically during file creation to prevent race conditions.

### Can I override stored credentials with environment variables?

Yes. The `get()` method in **agent_reach/config.py** implements a fallback mechanism that checks for environment variables using the uppercase version of the key name. This allows temporary overrides without modifying the persisted YAML file, ideal for ephemeral environments and secret injection.

### How does Agent Reach prevent secrets from appearing in logs?

The `to_dict()` method automatically masks any values associated with keys containing "key", "token", or "secret", displaying only the first eight characters followed by ellipsis. This ensures that accidental `print()` statements or debug logs do not expose full API keys or authentication tokens.