Secret Masking
Forge masks secrets in agent output before it writes trace files or streams output with frg --tail. This page lists the built-in detection patterns and explains how to handle false positives with a .gitleaks.toml allowlist.
How it works
Forge checks agent output against a built-in set of secret patterns and replaces each match with ***REDACTED***. Masking applies to trace files in .forge/work/job_<id>/traces/ and to live output from frg --tail.
Masking is pattern-based:
- It doesn't redact secrets that don't match a pattern.
- It doesn't rewrite trace files that already exist.
- It doesn't affect what the agent itself sends to its model provider or stores in its own logs.
For what Forge sends to agents, see the Security Guide.
What masking covers
Masking applies only to output that Forge itself produces:
- Covered: trace files in
.forge/work/job_<id>/traces/and livefrg --tailoutput. - Not covered: secrets already committed to version control, data the agent sends to its own model provider or writes to its own logs, and output from commands you run yourself outside Forge (for example,
catorechoin your shell).
Masking is also not retroactive: trace files written before a value matched a pattern aren't rewritten. Because detection is pattern-based, treat masking as a safety net rather than a guarantee. Keep credentials out of agent output in the first place, for example by referencing environment variables instead of printing their values.
Built-in patterns
| Pattern | Detects |
|---|---|
aws_access_key_id | AWS access key IDs |
aws_secret_access_key | aws_secret_access_key = <40-character value> assignments |
github_pat_classic, github_pat_fine_grained | GitHub personal access tokens (ghp_…, github_pat_…) |
github_oauth_token, github_refresh_token | GitHub OAuth (gho_…) and refresh (ghr_…) tokens; also ghs_… tokens |
bearer_token | Bearer <token> values |
generic_api_key | api_key, api-key, or apikey assigned a value of 20 or more characters |
private_key_header | -----BEGIN … PRIVATE KEY----- headers (RSA, EC, OPENSSH, PGP, DSA, ENCRYPTED) |
jwt_token | JSON Web Tokens (eyJ….eyJ….…) |
postgres_connection, mongodb_connection | PostgreSQL, MySQL, and MongoDB connection strings with user:password@ |
slack_token | Slack tokens (xoxb-, xoxa-, xoxp-, xoxr-, xoxs-) |
stripe_secret_key | Stripe live secret keys (sk_live_…) |
Configure an allowlist
Use .gitleaks.toml to stop Forge from masking values that match a pattern but aren't secrets, such as test fixtures or documentation placeholders. The file uses a gitleaks-style format.
Forge reads these keys:
| Key | Description |
|---|---|
title | Name of the configuration. |
[extend] useDefault | Keep the built-in patterns. Set to true. |
[allowlist] description | Description of the allowlist. |
[allowlist] regexes | Matches of these regular expressions are not masked. |
[allowlist] paths | Paths to exclude from masking. |
[allowlist] stopwords | Detected values that contain one of these words are not masked. |
Note: Forge's
.gitleaks.tomlmodel contains only the keys above. Custom[[rules]]entries are not part of it, so you can't add your own secret patterns this way. Keep credentials out of agent output instead, for example by using environment variables rather than printing values.
Example:
# .forge/config/.gitleaks.toml
title = "My project secret masking"
[extend]
useDefault = true
[allowlist]
description = "Values that look like secrets but aren't"
regexes = [
'''(test|example|dummy|fake|mock)_(key|secret|token|password)''',
'''<YOUR_[A-Z_]+>''',
]
paths = [
"test/fixtures/",
]
stopwords = ["example", "placeholder", "sample"]
Use TOML literal strings ('''…''') for regular expressions so backslashes don't need escaping.
File locations
Forge looks for .gitleaks.toml hierarchically. If it finds no file, or can't load it, Forge uses the built-in configuration.
| Priority | Location | Scope |
|---|---|---|
| 1 (highest) | .forge/config/.gitleaks.toml | Repository |
| 2 | <app_root>/.forge/config/.gitleaks.toml | Application (multi-repository) |
| 3 | ~/.forge/.gitleaks.toml | User |
| 4 | ~/.config/forge/.gitleaks.toml | System-wide |
| 5 (lowest) | Built-in defaults | — |
Commit the repository file to version control so the whole team uses the same allowlist.
Verify masking
- Run a workflow command with debug logging:
RUST_LOG=debug frg ask "Summarize the configuration files"
-
In the log output, look for
Secret masker initialized(with pattern, allowlist, and stopword counts),Masking detected secret, andSkipping allowlisted match. -
Search trace files for masked values:
grep -rF '***REDACTED***' .forge/work/*/traces/
Troubleshooting
Failed to parse gitleaks config at <path>
Cause: The file isn't valid TOML or uses an unexpected structure.
Solution:
- Check the file for syntax errors, such as unclosed strings or brackets.
- Keep only the keys listed in Configure an allowlist.
Until you fix the file, Forge uses the default configuration.
Failed to discover .gitleaks.toml hierarchically, using default configuration
Cause: Forge couldn't read a .gitleaks.toml file in the search hierarchy.
Solution:
- Check that the file is in one of the file locations.
- Check the file's read permissions.
Failed to compile allowlist pattern
Cause: An entry in [allowlist] regexes isn't a valid regular expression.
Solution:
- Test the regular expression separately.
- Write it as a TOML literal string (
'''…''') so backslashes are kept as written.
A value is masked but isn't a secret
Cause: The value matches a built-in pattern.
Solution: Add a matching entry to [allowlist] regexes, or add a distinguishing word to [allowlist] stopwords.
A secret appears in a trace file
Cause: The secret doesn't match a built-in pattern, or the trace file was written before masking applied to it.
Solution:
- Rotate the exposed credential.
- Delete or clean the affected trace file.
- Keep the credential out of agent output in future runs, for example by reading it from an environment variable.
See Also
- Security Guide — data flow, sensitive files, and safe customization
- Prompt Safety Validation — protection for agent input
- Security Workflow — SAST integration and vulnerability scanning
- Configuration Hierarchy
- Gitleaks configuration format