Security Model for Storing Credentials and Cookies in Agent Reach's config.yaml

Agent Reach stores all sensitive credentials in ~/.agent-reach/config.yaml using a three-layer defense strategy: strict POSIX filesystem permissions (0o700/0o600), runtime masking of secret values, and atomic file creation with owner-only access flags.

The Panniantong/Agent-Reach repository manages authentication secrets ranging from Twitter API tokens to XiaoHongShu session cookies. Understanding the security model for storing credentials and cookies in Agent Reach is essential for administrators deploying the tool on multi-user systems or shared development environments where unauthorized access to secrets could compromise automated agents.

Filesystem Permissions and Access Control

Agent Reach enforces owner-only filesystem permissions at the operating system level to prevent unauthorized reads by other users on the same machine.

The configuration directory ~/.agent-reach is created with mode 0o700 (read, write, and execute for owner only) through the make_private_dir function in agent_reach/utils/paths.py【/cache/repos/github.com/Panniantong/Agent-Reach/main/agent_reach/utils/paths.py#L10-L16】. This ensures that non-privileged users cannot list the directory contents or traverse into it.

The config.yaml file itself receives mode 0o600 (read/write for owner only) through a secure creation pattern implemented in agent_reach/config.py【/cache/repos/github.com/Panniantong/Agent-Reach/main/agent_reach/config.py#L54-L66】. The Config.save() method attempts to open the file using os.open(..., stat.S_IRUSR | stat.S_IWUSR), which atomically creates the file with restricted permissions. If the operating system does not support these flags, the code falls back to a standard open followed by os.chmod to enforce 0o600.

Runtime Masking of Sensitive Values

To prevent accidental leakage in logs and UI output, Agent Reach implements automatic masking of secret values when the configuration is displayed.

The Config.to_dict() method in agent_reach/config.py scans each configuration key for sensitive substrings including key, token, cookie, session, csrf, auth, cred, and ct0【/cache/repos/github.com/Panniantong/Agent-Reach/main/agent_reach/config.py#L108-L128】. When a match is detected, the method truncates the value to the first eight characters followed by an ellipsis, ensuring that debug output or CLI tables reveal only non-sensitive prefixes.

External Sync and Auxiliary Storage

For backward compatibility with other tools, Agent Reach optionally synchronizes Twitter credentials to auxiliary locations while maintaining the same security standards.

The _open_owner_only helper function in agent_reach/cookie_extract.py provides a reusable mechanism for creating files with 0o600 permissions【/cache/repos/github.com/Panniantong/Agent-Reach/main/agent_reach/cookie_extract.py#L49-L68】. This helper is utilized by two sync functions:

  • _sync_xfetch_session writes to ~/.config/xfetch/session.json【/cache/repos/github.com/Panniantong/Agent-Reach/main/agent_reach/cookie_extract.py#L75-L98】
  • _sync_bird_env writes to ~/.config/bird/credentials.env【/cache/repos/github.com/Panniantong/Agent-Reach/main/agent_reach/cookie_extract.py#L102-L124】

Both auxiliary files inherit the owner-only permission model, ensuring consistent protection across all credential storage locations.

The complete lifecycle of secret storage follows four distinct stages:

  1. Extraction – The cookie_extract.extract_all() function pulls cookies from browsers using rookiepy or browser_cookie3.
  2. Configuration – The configure_from_browser() method writes extracted values into the Config instance via config.set(key, value).
  3. Persistence – Each set() call triggers Config.save(), which writes the YAML with restricted 0o600 permissions.
  4. Masking – When callers request config.to_dict(), any secret value matching sensitive markers is masked before being returned.

The test suite in tests/test_config.py validates that directory and file permissions are correctly set to 0o700 and 0o600 respectively【/cache/repos/github.com/Panniantong/Agent-Reach/main/tests/test_config.py#L92-L104】, while also verifying that sensitive values appear masked in dictionary representations【/cache/repos/github.com/Panniantong/Agent-Reach/main/tests/test_config.py#L65-L71】.

Practical Configuration Example

The following example demonstrates secure credential storage and retrieval:

from agent_reach.config import Config

# Initialize creates ~/.agent-reach with 0o700 permissions

cfg = Config()  # Creates /home/user/.agent-reach/config.yaml

# Store secrets (file written with 0o600 atomic permissions)

cfg.set("twitter_auth_token", "my-super-secret-token")
cfg.set("xhs_cookie", "web_session=abc123; other=def456")

# Retrieve full value for API calls

token = cfg.get("twitter_auth_token")  # Returns full string

# Safe view for logging (automatically masked)

safe_cfg = cfg.to_dict()

# Output: {"twitter_auth_token": "my-supe...", "xhs_cookie": "web_ses..."}

Summary

  • Agent Reach stores credentials in ~/.agent-reach/config.yaml with owner-only POSIX permissions (0o600 for files, 0o700 for directories).
  • The Config.save() method uses os.open with stat.S_IRUSR | stat.S_IWUSR flags to atomically create restricted files, falling back to os.chmod when necessary.
  • Runtime masking in Config.to_dict() prevents secret leakage by truncating values containing sensitive markers (token, cookie, auth, etc.) to eight characters.
  • Auxiliary credential files in ~/.config/xfetch/ and ~/.config/bird/ receive identical 0o600 permissions through the _open_owner_only helper.
  • The implementation is validated by tests/test_config.py, which asserts correct permission bits and masking behavior.

Frequently Asked Questions

How does Agent Reach prevent other users from reading my API keys?

Agent Reach creates the configuration directory with 0o700 permissions and the config.yaml file with 0o600 permissions using the make_private_dir function in agent_reach/utils/paths.py and atomic file creation in Config.save(). These POSIX modes restrict read and write access exclusively to the file owner, preventing any other user on the system—including those with standard user privileges—from accessing your secrets.

What happens if the atomic open with permission flags fails?

If the operating system does not support the os.open flags stat.S_IRUSR | stat.S_IWUSR, the code in agent_reach/config.py falls back to a standard file open followed immediately by os.chmod to enforce 0o600 permissions. This ensures that even on limited platforms, the file does not remain world-readable even for a brief instant after creation.

Why are my credential values truncated when I print the configuration?

The Config.to_dict() method automatically masks any value associated with keys containing sensitive substrings like token, cookie, session, or auth. This deliberate defense-in-depth measure prevents accidental exposure of full secrets in log files, debug traces, or CLI output, showing only the first eight characters followed by an ellipsis.

Are credentials synced to external tools also protected?

Yes. When Agent Reach synchronizes Twitter credentials to ~/.config/xfetch/session.json or ~/.config/bird/credentials.env, it uses the _open_owner_only helper in agent_reach/cookie_extract.py. This function mirrors the secure file creation pattern of the main configuration, guaranteeing that auxiliary files also receive 0o600 permissions and remain accessible only to the owner.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →