# Agent Reach Credential Storage Security in config.yaml: A Technical Deep Dive

> Learn how Agent Reach secures API keys and secrets in config.yaml with 0o600 permissions and automatic masking. Protect your credentials with this technical guide.

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

---

**Agent Reach stores API keys and secrets in `~/.agent-reach/config.yaml` with strict 0o600 file permissions and automatic masking to prevent credential leakage.**

The **Panniantong/Agent-Reach** repository implements a defense-in-depth strategy for **Agent Reach credential storage security** by combining filesystem permissions, secure file handling, and runtime masking. Rather than scattering secrets across environment variables or plaintext files, the tool centralizes configuration in a single YAML file protected by Unix-style access controls and programmatic safeguards.

## Config File Location and Directory Isolation

Agent Reach creates a dedicated configuration directory in the user's home folder to isolate sensitive data from other applications. According to the source code in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py), the `Config` class initializes with a hardcoded path:

```python

# From agent_reach/config.py lines 18-20

self.config_dir = Path.home() / ".agent-reach"
self.config_file = self.config_dir / "config.yaml"

```

The `_ensure_dir` method automatically creates this hidden directory on first use. By confining all settings—including API keys for integrations like Exa Search—to `~/.agent-reach/`, the tool prevents accidental exposure through generic backup scripts or directory listings.

## Permission-Based Security Model

### Restricted File Permissions (0o600)

When persisting credentials, Agent Reach opens the YAML file using low-level `os.open` calls with explicit permission flags. The `save` method in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) (lines 52-60) enforces owner-only access:

```python
import os
import stat

# Create file with restrictive permissions atomically

fd = os.open(
    self.config_file,
    os.O_CREAT | os.O_WRONLY | os.O_TRUNC,
    stat.S_IRUSR | stat.S_IWUSR  # 0o600: read/write for owner only

)

```

This approach eliminates race conditions where the file might temporarily be world-readable during creation. On platforms where `os.open` flags are unsupported (e.g., Windows), the code falls back to standard `open()` calls, but the primary path ensures **credentials are never accessible to other users** on the system.

### Atomic Write Operations

The `save` method rewrites the entire configuration file for every modification, ensuring that permission checks run consistently. This explicit load-and-save cycle guarantees that any change to the [`config.yaml`](https://github.com/Panniantong/Agent-Reach/blob/main/config.yaml) structure goes through the secure pathway defined in the core configuration logic.

## Configuration API and Secure Access Patterns

### Explicit Load and Save Cycle

Upon instantiation, the `Config` class loads existing data using `yaml.safe_load` (lines 42-47 in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py)), preventing arbitrary code execution during YAML parsing. The API abstracts file handling through three primary methods:

- **`get(key, default)`**: Retrieves values from an in-memory dictionary, falling back to environment variables (matching `KEY.upper()`) if the key is absent from the file
- **`set(key, value)`**: Updates the dictionary and immediately persists to disk with 0o600 permissions
- **`delete(key)`**: Removes the entry and rewrites the file securely

### Feature-Based Requirement Checks

The `FEATURE_REQUIREMENTS` mapping (lines 21-28) defines which credential sets are mandatory for optional integrations. For example, the Exa Search feature requires `exa_api_key`. The `is_configured(feature)` method validates that all required secrets exist before allowing the CLI to execute integration-specific commands:

```python
from agent_reach.config import Config

cfg = Config()

# Check if Exa Search integration is ready

if cfg.is_configured("exa_search"):
    # Safe to use Exa API

    pass
else:
    print("Missing Exa API key in config.yaml")

```

## Sensitive Data Masking and Display Protection

To prevent credential leakage in logs or terminal output, the `to_dict` method (lines 102-108) implements automatic masking. When displaying configuration data—for example, during `agent_reach doctor` diagnostics—the method replaces any value whose key contains sensitive substrings with a truncated placeholder:

**Masked key patterns:**
- `key`
- `token`
- `password`
- `proxy`

Values matching these patterns appear as `abcd1234...` rather than the actual secret, allowing users to verify that credentials are set without exposing the raw strings.

## Practical Implementation Examples

The following pattern demonstrates secure credential management according to the [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) implementation:

```python
from agent_reach.config import Config

# Initialize (creates ~/.agent-reach/ with proper permissions if missing)

cfg = Config()

# Store API key (automatically saves with 0o600 permissions)

cfg.set("exa_api_key", "sk-live-xxxxxxxxxxxxxxxx")

# Retrieve with environment fallback

# Checks config.yaml first, then EXA_API_KEY env var

api_key = cfg.get("exa_api_key")

# Validate feature readiness before API calls

if cfg.is_configured("exa_search"):
    print("Exa Search ready")
else:
    raise ValueError("Configure exa_api_key first")

# Display-safe output (shows abcd1234... instead of real key)

safe_config = cfg.to_dict()

```

## Summary

- **Agent Reach stores credentials** in `~/.agent-reach/config.yaml` with 0o600 permissions enforced via `os.open` and `stat.S_IRUSR | stat.S_IWUSR`.
- The **Config class** in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) provides atomic write operations, environment variable fallback, and feature-based requirement validation.
- **Sensitive value masking** automatically protects keys containing "token", "key", "password", or "proxy" from appearing in diagnostic output.
- The isolation of configuration to a dedicated hidden directory prevents accidental inclusion in backups or version control.

## Frequently Asked Questions

### Where does Agent Reach store the config.yaml file?

Agent Reach stores the configuration file at `~/.agent-reach/config.yaml` in the user's home directory. The `Config` class automatically creates this path during initialization using `Path.home() / ".agent-reach"`, ensuring consistent location across all platforms while keeping the directory hidden from standard directory listings.

### What file permissions does Agent Reach use for credential storage?

The repository uses `stat.S_IRUSR | stat.S_IWUSR` (octal 0o600) when creating the YAML file, meaning only the file owner can read or write the contents. The `save` method in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) uses `os.open` with these flags to set permissions atomically at creation time, preventing the file from ever being world-readable.

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

When the `to_dict` method generates output for display (such as during `agent_reach doctor`), it checks if keys contain sensitive substrings like "key", "token", "password", or "proxy". Matching values are replaced with the masked placeholder `abcd1234...`, ensuring that diagnostic output and logging frameworks cannot capture the actual secrets.

### Can Agent Reach read credentials from environment variables?

Yes. The `get` method first checks the in-memory configuration dictionary, then falls back to environment variables using the uppercase version of the key (e.g., `EXA_API_KEY` for `exa_api_key`). This allows temporary overrides without modifying the filesystem-stored [`config.yaml`](https://github.com/Panniantong/Agent-Reach/blob/main/config.yaml), while the file remains the authoritative source of truth.