New to FORGE? Start a free 30-day trial

Secret Masking

Updated on Oct 1, 2026

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 live frg --tail output.
  • 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, cat or echo in 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

PatternDetects
aws_access_key_idAWS access key IDs
aws_secret_access_keyaws_secret_access_key = <40-character value> assignments
github_pat_classic, github_pat_fine_grainedGitHub personal access tokens (ghp_…, github_pat_…)
github_oauth_token, github_refresh_tokenGitHub OAuth (gho_…) and refresh (ghr_…) tokens; also ghs_… tokens
bearer_tokenBearer <token> values
generic_api_keyapi_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_tokenJSON Web Tokens (eyJ….eyJ….…)
postgres_connection, mongodb_connectionPostgreSQL, MySQL, and MongoDB connection strings with user:password@
slack_tokenSlack tokens (xoxb-, xoxa-, xoxp-, xoxr-, xoxs-)
stripe_secret_keyStripe 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:

KeyDescription
titleName of the configuration.
[extend] useDefaultKeep the built-in patterns. Set to true.
[allowlist] descriptionDescription of the allowlist.
[allowlist] regexesMatches of these regular expressions are not masked.
[allowlist] pathsPaths to exclude from masking.
[allowlist] stopwordsDetected values that contain one of these words are not masked.

Note: Forge's .gitleaks.toml model 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:

toml
# .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.

PriorityLocationScope
1 (highest).forge/config/.gitleaks.tomlRepository
2<app_root>/.forge/config/.gitleaks.tomlApplication (multi-repository)
3~/.forge/.gitleaks.tomlUser
4~/.config/forge/.gitleaks.tomlSystem-wide
5 (lowest)Built-in defaults—

Commit the repository file to version control so the whole team uses the same allowlist.

Verify masking

  1. Run a workflow command with debug logging:
bash
RUST_LOG=debug frg ask "Summarize the configuration files"
  1. In the log output, look for Secret masker initialized (with pattern, allowlist, and stopword counts), Masking detected secret, and Skipping allowlisted match.

  2. Search trace files for masked values:

bash
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:

  1. Check the file for syntax errors, such as unclosed strings or brackets.
  2. 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:

  1. Check that the file is in one of the file locations.
  2. Check the file's read permissions.

Failed to compile allowlist pattern

Cause: An entry in [allowlist] regexes isn't a valid regular expression.

Solution:

  1. Test the regular expression separately.
  2. 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:

  1. Rotate the exposed credential.
  2. Delete or clean the affected trace file.
  3. Keep the credential out of agent output in future runs, for example by reading it from an environment variable.

See Also