# How Agent Reach Stores Credentials Securely in config.yaml with 0600 Permissions

> Learn how Agent Reach securely stores credentials in config.yaml using 0600 permissions, protecting your sensitive API keys and tokens from unauthorized access. Discover the atomic file creation process for enhanced security.

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

---

**Agent Reach stores all API keys and tokens in `~/.agent-reach/config.yaml` with atomic file creation and strict `0600` permissions, ensuring only the file owner can read or write sensitive data.**

When building CLI tools that handle third-party API keys, protecting secrets from unauthorized access is critical. According to the Agent Reach source code, the project implements a defense-in-depth strategy that combines filesystem permissions, atomic writes, and runtime masking to keep credentials secure while maintaining usability.

## Understanding the Config Storage Location

All sensitive configuration data resides in a user-specific directory located at `~/.agent-reach/`. Within this directory, the [`config.yaml`](https://github.com/Panniantong/Agent-Reach/blob/main/config.yaml) file serves as the single source of truth for API keys, access tokens, and integration secrets.

The `Config` class defined in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) (lines 18-20) manages this file exclusively. When initialized, it automatically determines the correct path based on the user's home directory, ensuring that credentials are never stored in system-wide locations accessible to other users.

## Atomic File Creation with Permission Hardening

The core security mechanism resides in the `save()` method implemented in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) (lines 51-60). Rather than using standard file operations that could temporarily expose data, Agent Reach employs low-level system calls to guarantee permissions are set at creation time—before any data hits the disk.

The implementation uses `os.open()` with specific flags:

```python
import os
import stat

# Flags: Write-only, create if not exists, truncate if exists

flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC

# Mode: Owner read/write only (octal 0600)

mode = stat.S_IRUSR | stat.S_IWUSR

fd = os.open(filepath, flags, mode)

```

This approach eliminates race conditions where the file might exist with world-readable permissions (such as `0644` or `0640`) even for a fraction of a second. If the underlying operating system does not support these specific flags—for example, on Windows—the code gracefully falls back to a standard `open()` call, though the primary path ensures Unix-like systems maintain strict security boundaries.

## Security Mechanisms

Agent Reach employs three distinct pillars to protect sensitive configuration data.

### User-Only Storage Location

The configuration directory lives under the user's home directory (`~/.agent-reach`), ensuring that the operating system's standard user isolation prevents other system users from accessing the directory contents. This provides the first layer of defense through standard Unix file ownership models.

### Permission-Hardening at Creation

By creating [`config.yaml`](https://github.com/Panniantong/Agent-Reach/blob/main/config.yaml) with `0600` permissions (owner read/write only), the `save()` method ensures no other user or group can access the file contents. This is implemented through bitwise OR operations combining `stat.S_IRUSR` and `stat.S_IWUSR`, which translates precisely to octal `0600`.

### Masking Sensitive Values

When configurations are displayed in logs or CLI output, the `to_dict()` method (lines 101-108 in [`config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/config.py)) automatically masks sensitive values. This prevents accidental credential leakage through shell history, log files, or terminal output, ensuring that even if a user prints the configuration object, secrets remain hidden.

## Working with Credentials

The `Config` class provides a simple interface for storing and retrieving credentials while automatically enforcing security controls.

**Saving a new API key (automatically enforces `0600` permissions):**

```python
from agent_reach.config import Config

cfg = Config()
cfg.set("exa_api_key", "sk-XXXXXXXXXXXXXXXX")

```

**Loading a credential (checks file first, then environment variables):**

```python
cfg = Config()
exa_key = cfg.get("exa_api_key")  # Returns the stored key or None

```

**Inspecting the stored config without revealing secrets:**

```python
cfg = Config()
print(cfg.to_dict())

# Output shows masked value like "exa_api_key": "sk-XXXX..."

```

## Summary

- **Agent Reach stores credentials** in `~/.agent-reach/config.yaml` with strict `0600` permissions enforced at file creation.
- **Atomic writes** using `os.open()` with `O_WRONLY | O_CREAT | O_TRUNC` and mode `stat.S_IRUSR | stat.S_IWUSR` prevent race conditions where files might be temporarily exposed.
- **Automatic masking** in `to_dict()` prevents credential leaks through logs and terminal output.
- **Test coverage** in [`tests/test_config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/tests/test_config.py) validates correct loading, saving, and permission behavior across platforms.

## Frequently Asked Questions

### What does 0600 permission mean in Agent Reach?

The `0600` permission setting means only the file owner has read and write access, while group members and other users have no permissions whatsoever. In Agent Reach, this is implemented using `stat.S_IRUSR | stat.S_IWUSR` when calling `os.open()` in the `save()` method, ensuring secrets are never world-readable.

### How does Agent Reach prevent credentials from being exposed during file creation?

Agent Reach uses atomic file creation via `os.open()` with flags `O_WRONLY | O_CREAT | O_TRUNC` combined with the `0600` mode mask. This ensures the file is created with correct permissions from the very first moment it exists on the filesystem, eliminating the window where temporary files might be readable by others.

### Can I use environment variables instead of config.yaml for sensitive data?

Yes. The `Config.get()` method checks environment variables as a fallback mechanism. If a key is not found in [`config.yaml`](https://github.com/Panniantong/Agent-Reach/blob/main/config.yaml), the system looks for corresponding environment variables, allowing you to keep credentials entirely outside the filesystem if your security policy requires it.

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

The configuration file is stored at `~/.agent-reach/config.yaml` relative to the user's home directory. This location is determined by the `Config` class initialization logic in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py), ensuring user-specific isolation regardless of where the Python process is executed.