# How Agent Reach Handles Secure Storage of Credentials and File Permissions

> Agent Reach secures credentials and file permissions by storing them in config.yaml with 0o600 permissions and masking sensitive data. Learn how to prevent credential exposure.

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

---

**Agent Reach stores all API keys, tokens, and secrets in ~/.agent-reach/config.yaml with strict 0o600 file permissions, masks sensitive values in diagnostic output, and optionally falls back to environment variables to prevent accidental credential exposure.**

Agent Reach is an open-source automation framework that manages sensitive credentials for various APIs and services. The project implements a defense-in-depth approach to credential security through the **Config** class in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py), which centralizes all read and write operations to a single, protected YAML file in the user's home directory.

## Secure Storage Architecture

The credential storage system relies on a singleton YAML file located at `~/.agent-reach/config.yaml`. This design consolidates all secrets into one location where strict permissions can be enforced.

### File Permissions and Creation Flags

When writing the configuration file, the **Config** class uses low-level operating system flags to prevent unauthorized access. In [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py), the `save()` method opens the file with `os.open(..., stat.S_IRUSR | stat.S_IWUSR)`, which corresponds to mode **0o600** (read/write for owner only).

If the low-level `os.open` flags are unavailable—such as on Windows—the code falls back to a standard `open()` call, but the directory creation via `mkdir(parents=True, exist_ok=True)` still minimizes exposure by ensuring the path exists before any write operation.

### Directory Structure and Initialization

The `_ensure_dir()` method creates the `~/.agent-reach` directory on first use. This guarantees that the parent directory exists before any credential writes, preventing race conditions or permission inheritance issues from temporary directories.

## Security Mechanisms in the Config Class

The **Config** class implements multiple layers of protection beyond file permissions to prevent accidental credential leakage.

### Environment Variable Fallback

The `Config.get()` method checks the YAML configuration file first, then falls back to environment variables using `os.environ.get(key.upper())`. This allows users to keep sensitive values out of the filesystem entirely by exporting them as environment variables, reducing the risk of file-based credential exposure.

### Sensitive Value Masking

When displaying configuration data, `Config.to_dict()` automatically masks values for any key containing `"key"`, `"token"`, `"password"`, or `"proxy"`. These values are truncated to the first eight characters followed by an ellipsis (e.g., `abcd1234...`), ensuring that diagnostic output or logs never reveal full secrets.

### Centralized Write Path

All CLI commands and helper functions store credentials through `Config.set()`. This guarantees that every write operation passes through the same permission-controlled routine in `Config.save()`, preventing third-party code from bypassing security measures and writing credentials with world-readable permissions.

## Third-Party Tool Integration

Agent Reach synchronizes credentials with auxiliary tools while maintaining consistent security standards.

### Legacy Credential Sync

When importing Twitter cookies, the helper functions in [`agent_reach/cookie_extract.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/cookie_extract.py) write the same secrets to `~/.config/xfetch/session.json` and `~/.config/bird/credentials.env`. These auxiliary files are also created with mode **0o600**, ensuring that credentials remain protected even when shared with external tools.

## Practical Implementation Examples

### Setting Credentials via CLI

Use the `configure` command to store credentials securely:

```bash

# Set a GitHub token

agent-reach configure github-token ghp_XXXXXXXXXXXXXXXXXXXX

```

Behind the scenes, the CLI parses the input and calls `config.set("github_token", value)`, which triggers the `save()` routine with `0o600` permissions.

### Programmatic Credential Management

```python
from agent_reach.config import Config

cfg = Config()  # Loads ~/.agent-reach/config.yaml

cfg.set("exa_api_key", "sk-abc123")  # Saves with secure permissions

print(cfg.to_dict())  # Output: {'exa_api_key': 'sk-abc12...'}

```

### Reading with Environment Fallback

```python
import os
os.environ["EXA_API_KEY"] = "sk-xyz987"

from agent_reach.config import Config
cfg = Config()
key = cfg.get("exa_api_key")  # Returns "sk-xyz987" from environment

```

### Verifying File Permissions

Confirm that credentials are protected at the filesystem level:

```bash
$ ls -l ~/.agent-reach/config.yaml
-rw------- 1 user user 1234 Jun  6 12:34 /home/user/.agent-reach/config.yaml

```

The `-rw-------` mode confirms that only the file owner can read or write the configuration.

## Summary

- **Agent Reach stores all credentials in ~/.agent-reach/config.yaml** with strict 0o600 permissions enforced via `os.open()` flags in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py).
- **The Config class masks sensitive values** containing "key", "token", "password", or "proxy" when displaying configuration via `to_dict()`.
- **Environment variable fallback** in `Config.get()` allows users to keep secrets out of the filesystem entirely.
- **Centralized writes through Config.set()** ensure that all credentials pass through the same permission-controlled save routine.
- **Legacy sync in cookie_extract.py** extends 0o600 permissions to auxiliary files like `~/.config/xfetch/session.json`.

## Frequently Asked Questions

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

Agent Reach creates the `~/.agent-reach/config.yaml` file with mode **0o600** (read/write for owner only) using `os.open()` with `stat.S_IRUSR | stat.S_IWUSR` flags. This prevents other users on the system from accessing API keys, tokens, or passwords stored in the file.

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

The `Config.to_dict()` method in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) automatically masks any value where the key contains "key", "token", "password", or "proxy". It displays only the first eight characters followed by an ellipsis (e.g., `abcd1234...`), ensuring that diagnostic output and logs never expose complete secrets.

### Can I use environment variables instead of the config file?

Yes. The `Config.get()` method checks the YAML file first, then falls back to environment variables using `os.environ.get(key.upper())`. If you set `EXA_API_KEY` in your environment, `cfg.get("exa_api_key")` will return that value without reading from the config file, allowing you to keep credentials out of persistent storage.

### Does Agent Reach protect credentials when syncing with third-party tools?

Yes. When the [`cookie_extract.py`](https://github.com/Panniantong/Agent-Reach/blob/main/cookie_extract.py) module syncs Twitter credentials to auxiliary files like `~/.config/xfetch/session.json` or `~/.config/bird/credentials.env`, it explicitly sets file mode **0o600** on these files as well, maintaining consistent security standards across all credential storage locations.