fix(safety): add credential patterns and sensitive path blocklist - #1675
Conversation
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the security posture of the system by expanding its ability to detect and prevent the leakage of sensitive credentials. It introduces new patterns for various API keys and tokens within the leak detector and establishes a comprehensive blocklist for file system access to common credential storage locations. These changes are crucial for hardening the application against credential exfiltration and unauthorized file manipulation, discovered through proactive security testing. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request enhances security by adding new leak detection patterns for various API keys (OpenRouter, Anthropic OAuth, Telegram, Groq) and implementing a sensitive file path blocklist for file access tools. The is_sensitive_path function was introduced to prevent ReadFileTool, WriteFileTool, and ApplyPatchTool from interacting with credential-bearing files like .env or .ssh configurations. Feedback suggests that the sensitive path check needs to be made platform-agnostic by normalizing path separators, and the new leak detection regexes should incorporate word boundaries to prevent false positives and ensure consistency.
zmanian
left a comment
There was a problem hiding this comment.
Security Review: credential patterns and sensitive path blocklist
Solid security hardening. Good credential patterns for OpenRouter/Anthropic OAuth/Telegram/Groq. However:
Critical
ListDirToolnot guarded:ReadFileTool,WriteFileTool,ApplyPatchToolgetis_sensitive_pathchecks butListDirTooldoes not. Attacker can enumerate~/.ssh/,~/.aws/,~/.gnupg/contents.
High
- Shell tool bypass:
cat ~/.ssh/id_rsavia the shell tool trivially reads any sensitive file. At minimum document as known limitation with a tracking issue.
Medium
- Missing sensitive paths:
~/.config/gh/hosts.yml(GitHub CLI),/etc/shadow,~/.terraform.d/credentials.tfrc.json. - No test for path traversal bypass (
../../.ssh/id_rsa).canonicalize()should handle it but an explicit test would strengthen confidence.
Low
- Telegram pattern
\d{8,12}:AAcould false-match log lines with timestamps. Low risk but document the:AArequirement.
Positive
- Credential patterns are well-crafted with appropriate minimum lengths
- Symlink-through-canonicalize defense is correct
.env.example/.env.localsafe suffixes are thoughtful- 6 tests covering credential detection
Fix the ListDirTool gap and track the shell bypass before merge.
Addresses critical credential leakage found by security testing (~/.ironclaw/tests/SECURITY_REPORT.md, test ce-02). Leak detector (crates/ironclaw_safety/src/leak_detector.rs): - Add OpenRouter API key pattern (sk-or-v1-<hex>) - Add Anthropic OAuth token pattern (sk-ant-oat<NN>-<base64url>) - Add Telegram bot token pattern (word-bounded, 8-12 digit bot ID) - Add Groq API key pattern (gsk_<alphanumeric>) - 12 new tests with synthetic keys (positive, false-positive, integration) File tools (src/tools/builtin/file.rs): - Add sensitive path blocklist to ReadFileTool, WriteFileTool, and ApplyPatchTool (defense-in-depth for all file access vectors) - Blocks: .env (and .env.local/.env.production/etc.), .ssh/, .aws/, .netrc, .pgpass, .npmrc, .pypirc, .docker/config.json, .kube/config, .git-credentials, .gcloud/, .config/gcloud/, .gnupg/, .vault-token, .ironclaw/secrets/ - Allows .env.example, .env.template, .env.sample (safe suffixes) - Case-insensitive; resolves symlinks via canonicalize() before check - 8 new tests covering blocking, safe suffixes, .env variants, case Known gap: shell tool can still `cat ~/.env` — different security domain (denylist-gated in autonomous mode, user-initiated in interactive mode). Tracked for follow-up. Note: new patterns use .unwrap() on Regex::new() matching the established convention of the 16 existing patterns in this file (all use // safety: hardcoded literal). Follow-up to address the existing .unwrap() debt across all patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…blocklist - Move is_sensitive_path to ironclaw_safety crate for shared use - Guard ListDirTool with sensitive path checks (including recursive traversal) - Add missing sensitive paths: ~/.config/gh/hosts.yml, /etc/shadow, ~/.terraform.d/credentials.tfrc.json, ~/.azure/ - Add path traversal regression test and ListDirTool blocking test Addresses review feedback from zmanian, gemini-code-assist, and copilot. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When ListDirTool's recursive traversal encounters a sensitive directory, annotate it with [sensitive - access blocked] so users understand why its contents are suppressed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
84f574b to
d9ba583
Compare
zmanian
left a comment
There was a problem hiding this comment.
Re-review: credential patterns and sensitive path blocklist
3 of 4 original findings fixed. Good progress.
| Finding | Status |
|---|---|
| CRITICAL: ListDirTool not guarded | Fixed -- blocks sensitive dirs, annotates as [sensitive - access blocked] |
| HIGH: Shell tool bypass | Still open -- cat/head/less on protected paths still works via shell tool |
| MEDIUM: Missing sensitive paths | Fixed -- added gh/hosts.yml, /etc/shadow, terraform, azure |
| MEDIUM: No path traversal test | Fixed -- canonicalize + raw string matching tests |
The shell tool bypass remains the main gap. Consider synchronizing DANGEROUS_PATTERNS with SENSITIVE_PATH_PATTERNS, or integrating is_sensitive_path() into shell argument scanning.
…hecking Add defense-in-depth check for shell commands that read sensitive credential files (cat, head, tail, less, cp, etc.). Extracts file path arguments from known file-reading commands and checks them against the shared is_sensitive_path function from ironclaw_safety. This is best-effort — shell-level bypass via aliases, variable expansion, or encoding is still possible. Full mitigation requires filesystem-level sandboxing (seccomp/landlock). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Addressed in 46e2846: integrated What's covered:
Known limitation (documented): Shell-level bypass via aliases, variable expansion, encoding, or non-listed commands remains possible. This is defense-in-depth, not a complete fix. Full mitigation requires filesystem-level sandboxing (seccomp/landlock). Validation: |
|
Re-review of 46e2846 - posting detailed review |
zmanian
left a comment
There was a problem hiding this comment.
Re-review: shell tool integration (commit 46e2846)
The new commit addresses the HIGH-priority shell tool bypass. Good progress.
What was done well
- Correct placement:
check_sensitive_file_accessruns after injection detection, before execution - Shared
is_sensitive_pathreuse fromironclaw_safety-- no duplicated logic - Tilde expansion, pipe/semicolon splitting, input redirection, full-path command stripping all handled
- Honest documentation: clearly states this is defense-in-depth, not a complete sandbox
- 8 regression tests covering key scenarios
Previous findings status
All 4 previous findings (ListDirTool, shell bypass, missing paths, traversal test) are fixed.
New findings
Important (should fix):
-
Output redirection bypass: The function checks read commands but not write targets via
>or>>. An attacker could write to sensitive credential paths via redirection. Consider scanning redirect targets againstis_sensitive_path. This mirrors the existing comment on line 902 about redirect-aware parsing. -
Subshell / command substitution bypass:
$()and backtick substitution not handled. A sensitive read nested in command substitution would not be caught. Exploitability is lower sincedetect_command_injectionpartially covers this upstream. Document the gap. -
Ampersand splitting fragility: Splitting on single
&incorrectly splits&&into segments. Works by accident (empty segment is harmless) but is fragile. Consider splitting on["&&", "||", "|", ";"]explicitly.
Verdict
Meaningful security improvement that closes the most obvious bypass. Known limitations honestly documented. Items 1-3 worth addressing before merge -- item 1 (output redirection) is most actionable as the write-path equivalent of the read-path protection this commit adds.
Overall: good security work. Substantially better than at the start of the review cycle.
Address zmanian's re-review findings: - Check > and >> redirection targets against is_sensitive_path (write-path equivalent of read-path protection) - Replace single-char & splitting with proper &&/|| aware parser to avoid fragmenting double operators - Document subshell/command-substitution gap (partially covered by detect_command_injection upstream) - Extract helpers: split_shell_segments, check_segment_file_commands, check_redirect_target, expand_tilde - Add tests for output redirection, chained commands, segment splitting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Addressed all 3 findings from re-review in 8175f93:
Also refactored into smaller helpers: Validation: |
zmanian
left a comment
There was a problem hiding this comment.
Request Changes
Credential patterns are well-crafted (all ReDoS-safe). Putting is_sensitive_path in ironclaw_safety is architecturally correct. However, there's a critical conflict.
Must-fix
-
Direct conflict with PR #1713 -- both implement sensitive path protection, touching the exact same insertion points in
file.rsandshell.rs. Recommend: use this PR as base (safety crate is the right home), absorb #1713's more complete path list, close #1713 as superseded. -
Telegram pattern needs trailing
\b--\b\d{8,12}:AA[A-Za-z0-9_-]{30,}could false-positive on structured data.
Should-fix
- Missing patterns from #1713:
.bash_history,.zsh_history,.histfile,/etc/gshadow, key extensions (.pem,.key,.p12,.pfx), individual key files (id_ed25519,id_ecdsa,id_dsa) grepmissing fromFILE_READ_COMMANDS-- also considerawk,sed,python,curlcheck_redirect_targetonly finds first>or<per segment.enverror message should point to specific IronClaw secrets management commands
zmanian
left a comment
There was a problem hiding this comment.
Re-review: commit 339977a (fix 3 items from previous review)
All 3 medium findings from my last review are addressed:
| Finding | Status | Notes |
|---|---|---|
Blocking canonicalize() in async context |
Addressed | Documented trade-off with guidance to make async if needed. Pragmatic -- local FS is sub-ms. |
| Overly broad standalone SSH key patterns | Fixed | Moved to SENSITIVE_FILENAMES with exact file_name() match. Test confirms grid_rsa_data no longer false-positives. |
| Duplicate test suites | Fixed | Removed duplicate is_sensitive_path unit tests from file.rs. Only integration-level execute() test remains. |
No new issues in this commit. LGTM.
|
Hey! 👋 Just checking in — this one's still good to go (no conflicts with staging). Would appreciate a re-review when you have a moment! @ilblackdragon @serrrfirat |
|
Reviewing the full worktree relative to Findings:
Residual risk:
|
|
Thanks for the thorough review @serrrfirat! 🙏 I've looked at all three findings — they're all pre-existing issues inherited from the staging base branch, not introduced by this PR's sensitive-path protection changes:
Happy to file separate issues for these if the maintainers want them tracked. Our diff is limited to |
…arai#1675) * fix(safety): add credential patterns and sensitive path blocklist Addresses critical credential leakage found by security testing (~/.ironclaw/tests/SECURITY_REPORT.md, test ce-02). Leak detector (crates/ironclaw_safety/src/leak_detector.rs): - Add OpenRouter API key pattern (sk-or-v1-<hex>) - Add Anthropic OAuth token pattern (sk-ant-oat<NN>-<base64url>) - Add Telegram bot token pattern (word-bounded, 8-12 digit bot ID) - Add Groq API key pattern (gsk_<alphanumeric>) - 12 new tests with synthetic keys (positive, false-positive, integration) File tools (src/tools/builtin/file.rs): - Add sensitive path blocklist to ReadFileTool, WriteFileTool, and ApplyPatchTool (defense-in-depth for all file access vectors) - Blocks: .env (and .env.local/.env.production/etc.), .ssh/, .aws/, .netrc, .pgpass, .npmrc, .pypirc, .docker/config.json, .kube/config, .git-credentials, .gcloud/, .config/gcloud/, .gnupg/, .vault-token, .ironclaw/secrets/ - Allows .env.example, .env.template, .env.sample (safe suffixes) - Case-insensitive; resolves symlinks via canonicalize() before check - 8 new tests covering blocking, safe suffixes, .env variants, case Known gap: shell tool can still `cat ~/.env` — different security domain (denylist-gated in autonomous mode, user-initiated in interactive mode). Tracked for follow-up. Note: new patterns use .unwrap() on Regex::new() matching the established convention of the 16 existing patterns in this file (all use // safety: hardcoded literal). Follow-up to address the existing .unwrap() debt across all patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Update src/tools/builtin/file.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * fix(safety): address review feedback on credential patterns and path blocklist - Move is_sensitive_path to ironclaw_safety crate for shared use - Guard ListDirTool with sensitive path checks (including recursive traversal) - Add missing sensitive paths: ~/.config/gh/hosts.yml, /etc/shadow, ~/.terraform.d/credentials.tfrc.json, ~/.azure/ - Add path traversal regression test and ListDirTool blocking test Addresses review feedback from zmanian, gemini-code-assist, and copilot. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): annotate sensitive dirs as blocked in recursive listing When ListDirTool's recursive traversal encounters a sensitive directory, annotate it with [sensitive - access blocked] so users understand why its contents are suppressed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): integrate is_sensitive_path into shell tool file-access checking Add defense-in-depth check for shell commands that read sensitive credential files (cat, head, tail, less, cp, etc.). Extracts file path arguments from known file-reading commands and checks them against the shared is_sensitive_path function from ironclaw_safety. This is best-effort — shell-level bypass via aliases, variable expansion, or encoding is still possible. Full mitigation requires filesystem-level sandboxing (seccomp/landlock). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): add output redirection checks, fix segment splitting Address zmanian's re-review findings: - Check > and >> redirection targets against is_sensitive_path (write-path equivalent of read-path protection) - Replace single-char & splitting with proper &&/|| aware parser to avoid fragmenting double operators - Document subshell/command-substitution gap (partially covered by detect_command_injection upstream) - Extract helpers: split_shell_segments, check_segment_file_commands, check_redirect_target, expand_tilde - Add tests for output redirection, chained commands, segment splitting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(safety): address PR nearai#1675 review feedback and absorb nearai#1713 patterns Absorb nearai#1713's sensitive path patterns into ironclaw_safety crate: - Add shell history files, SSH key types, /etc/gshadow - Add sensitive file extensions (.pem, .key, .p12, .pfx, .jks, .keystore) - Add .dist safe suffix; smart .env matching (excludes .envrc, .environment) - Directory-level blocking for .aws/, .docker/, .kube/ (not just specific files) - Trailing-slash matching so bare directory paths trigger detection Shell tool hardening: - Strip surrounding quotes from tokens before sensitive path check - Add grep, awk, sed to FILE_READ_COMMANDS - Scan ALL redirect operators in a segment, not just the first Other fixes: - Add trailing \b to Telegram bot token regex to prevent over-matching - Update error messages to reference secret_list/secret_create - Strengthen ListDirTool test with tempfile-based .ssh directory Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(safety): close 4 adversarial bypass vectors in leak detector - Fix .env suffix check: use exact remainder matching instead of ends_with, so .env.production.dist is no longer allowed through - Detect process substitution <(...) in redirect checks and scan inner tokens for sensitive paths - Add missing /id_rsa to SENSITIVE_PATH_PATTERNS (other SSH key types were already present) - Check --flag=value tokens for sensitive paths instead of skipping all tokens starting with - Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix 3 items from zmanian re-review on leak detector 1. Document blocking canonicalize() in async context: added comment explaining the trade-off (sub-ms on local FS, could block on NFS) with guidance to make async if needed. 2. Fix overly broad standalone key patterns: moved id_rsa, id_ed25519, id_ecdsa, id_dsa, authorized_keys, known_hosts from substring-based SENSITIVE_PATH_PATTERNS to exact filename matching via SENSITIVE_FILENAMES. This prevents false positives on paths like /project/grid_rsa_data while still blocking /project/test_fixtures/id_rsa. 3. Remove duplicate is_sensitive_path unit tests from file.rs: these belong in sensitive_paths.rs which already has comprehensive coverage. Kept integration-level tests that exercise tool execute() methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: j-bloggs <j-bloggs@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…arai#1675) * fix(safety): add credential patterns and sensitive path blocklist Addresses critical credential leakage found by security testing (~/.ironclaw/tests/SECURITY_REPORT.md, test ce-02). Leak detector (crates/ironclaw_safety/src/leak_detector.rs): - Add OpenRouter API key pattern (sk-or-v1-<hex>) - Add Anthropic OAuth token pattern (sk-ant-oat<NN>-<base64url>) - Add Telegram bot token pattern (word-bounded, 8-12 digit bot ID) - Add Groq API key pattern (gsk_<alphanumeric>) - 12 new tests with synthetic keys (positive, false-positive, integration) File tools (src/tools/builtin/file.rs): - Add sensitive path blocklist to ReadFileTool, WriteFileTool, and ApplyPatchTool (defense-in-depth for all file access vectors) - Blocks: .env (and .env.local/.env.production/etc.), .ssh/, .aws/, .netrc, .pgpass, .npmrc, .pypirc, .docker/config.json, .kube/config, .git-credentials, .gcloud/, .config/gcloud/, .gnupg/, .vault-token, .ironclaw/secrets/ - Allows .env.example, .env.template, .env.sample (safe suffixes) - Case-insensitive; resolves symlinks via canonicalize() before check - 8 new tests covering blocking, safe suffixes, .env variants, case Known gap: shell tool can still `cat ~/.env` — different security domain (denylist-gated in autonomous mode, user-initiated in interactive mode). Tracked for follow-up. Note: new patterns use .unwrap() on Regex::new() matching the established convention of the 16 existing patterns in this file (all use // safety: hardcoded literal). Follow-up to address the existing .unwrap() debt across all patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Update src/tools/builtin/file.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * fix(safety): address review feedback on credential patterns and path blocklist - Move is_sensitive_path to ironclaw_safety crate for shared use - Guard ListDirTool with sensitive path checks (including recursive traversal) - Add missing sensitive paths: ~/.config/gh/hosts.yml, /etc/shadow, ~/.terraform.d/credentials.tfrc.json, ~/.azure/ - Add path traversal regression test and ListDirTool blocking test Addresses review feedback from zmanian, gemini-code-assist, and copilot. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): annotate sensitive dirs as blocked in recursive listing When ListDirTool's recursive traversal encounters a sensitive directory, annotate it with [sensitive - access blocked] so users understand why its contents are suppressed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): integrate is_sensitive_path into shell tool file-access checking Add defense-in-depth check for shell commands that read sensitive credential files (cat, head, tail, less, cp, etc.). Extracts file path arguments from known file-reading commands and checks them against the shared is_sensitive_path function from ironclaw_safety. This is best-effort — shell-level bypass via aliases, variable expansion, or encoding is still possible. Full mitigation requires filesystem-level sandboxing (seccomp/landlock). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): add output redirection checks, fix segment splitting Address zmanian's re-review findings: - Check > and >> redirection targets against is_sensitive_path (write-path equivalent of read-path protection) - Replace single-char & splitting with proper &&/|| aware parser to avoid fragmenting double operators - Document subshell/command-substitution gap (partially covered by detect_command_injection upstream) - Extract helpers: split_shell_segments, check_segment_file_commands, check_redirect_target, expand_tilde - Add tests for output redirection, chained commands, segment splitting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(safety): address PR nearai#1675 review feedback and absorb nearai#1713 patterns Absorb nearai#1713's sensitive path patterns into ironclaw_safety crate: - Add shell history files, SSH key types, /etc/gshadow - Add sensitive file extensions (.pem, .key, .p12, .pfx, .jks, .keystore) - Add .dist safe suffix; smart .env matching (excludes .envrc, .environment) - Directory-level blocking for .aws/, .docker/, .kube/ (not just specific files) - Trailing-slash matching so bare directory paths trigger detection Shell tool hardening: - Strip surrounding quotes from tokens before sensitive path check - Add grep, awk, sed to FILE_READ_COMMANDS - Scan ALL redirect operators in a segment, not just the first Other fixes: - Add trailing \b to Telegram bot token regex to prevent over-matching - Update error messages to reference secret_list/secret_create - Strengthen ListDirTool test with tempfile-based .ssh directory Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(safety): close 4 adversarial bypass vectors in leak detector - Fix .env suffix check: use exact remainder matching instead of ends_with, so .env.production.dist is no longer allowed through - Detect process substitution <(...) in redirect checks and scan inner tokens for sensitive paths - Add missing /id_rsa to SENSITIVE_PATH_PATTERNS (other SSH key types were already present) - Check --flag=value tokens for sensitive paths instead of skipping all tokens starting with - Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix 3 items from zmanian re-review on leak detector 1. Document blocking canonicalize() in async context: added comment explaining the trade-off (sub-ms on local FS, could block on NFS) with guidance to make async if needed. 2. Fix overly broad standalone key patterns: moved id_rsa, id_ed25519, id_ecdsa, id_dsa, authorized_keys, known_hosts from substring-based SENSITIVE_PATH_PATTERNS to exact filename matching via SENSITIVE_FILENAMES. This prevents false positives on paths like /project/grid_rsa_data while still blocking /project/test_fixtures/id_rsa. 3. Remove duplicate is_sensitive_path unit tests from file.rs: these belong in sensitive_paths.rs which already has comprehensive coverage. Kept integration-level tests that exercise tool execute() methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: j-bloggs <j-bloggs@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> (cherry picked from commit e7fa167)
…arai#1675) * fix(safety): add credential patterns and sensitive path blocklist Addresses critical credential leakage found by security testing (~/.ironclaw/tests/SECURITY_REPORT.md, test ce-02). Leak detector (crates/ironclaw_safety/src/leak_detector.rs): - Add OpenRouter API key pattern (sk-or-v1-<hex>) - Add Anthropic OAuth token pattern (sk-ant-oat<NN>-<base64url>) - Add Telegram bot token pattern (word-bounded, 8-12 digit bot ID) - Add Groq API key pattern (gsk_<alphanumeric>) - 12 new tests with synthetic keys (positive, false-positive, integration) File tools (src/tools/builtin/file.rs): - Add sensitive path blocklist to ReadFileTool, WriteFileTool, and ApplyPatchTool (defense-in-depth for all file access vectors) - Blocks: .env (and .env.local/.env.production/etc.), .ssh/, .aws/, .netrc, .pgpass, .npmrc, .pypirc, .docker/config.json, .kube/config, .git-credentials, .gcloud/, .config/gcloud/, .gnupg/, .vault-token, .ironclaw/secrets/ - Allows .env.example, .env.template, .env.sample (safe suffixes) - Case-insensitive; resolves symlinks via canonicalize() before check - 8 new tests covering blocking, safe suffixes, .env variants, case Known gap: shell tool can still `cat ~/.env` — different security domain (denylist-gated in autonomous mode, user-initiated in interactive mode). Tracked for follow-up. Note: new patterns use .unwrap() on Regex::new() matching the established convention of the 16 existing patterns in this file (all use // safety: hardcoded literal). Follow-up to address the existing .unwrap() debt across all patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Update src/tools/builtin/file.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Update crates/ironclaw_safety/src/leak_detector.rs Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * fix(safety): address review feedback on credential patterns and path blocklist - Move is_sensitive_path to ironclaw_safety crate for shared use - Guard ListDirTool with sensitive path checks (including recursive traversal) - Add missing sensitive paths: ~/.config/gh/hosts.yml, /etc/shadow, ~/.terraform.d/credentials.tfrc.json, ~/.azure/ - Add path traversal regression test and ListDirTool blocking test Addresses review feedback from zmanian, gemini-code-assist, and copilot. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): annotate sensitive dirs as blocked in recursive listing When ListDirTool's recursive traversal encounters a sensitive directory, annotate it with [sensitive - access blocked] so users understand why its contents are suppressed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): integrate is_sensitive_path into shell tool file-access checking Add defense-in-depth check for shell commands that read sensitive credential files (cat, head, tail, less, cp, etc.). Extracts file path arguments from known file-reading commands and checks them against the shared is_sensitive_path function from ironclaw_safety. This is best-effort — shell-level bypass via aliases, variable expansion, or encoding is still possible. Full mitigation requires filesystem-level sandboxing (seccomp/landlock). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tools): add output redirection checks, fix segment splitting Address zmanian's re-review findings: - Check > and >> redirection targets against is_sensitive_path (write-path equivalent of read-path protection) - Replace single-char & splitting with proper &&/|| aware parser to avoid fragmenting double operators - Document subshell/command-substitution gap (partially covered by detect_command_injection upstream) - Extract helpers: split_shell_segments, check_segment_file_commands, check_redirect_target, expand_tilde - Add tests for output redirection, chained commands, segment splitting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(safety): address PR nearai#1675 review feedback and absorb nearai#1713 patterns Absorb nearai#1713's sensitive path patterns into ironclaw_safety crate: - Add shell history files, SSH key types, /etc/gshadow - Add sensitive file extensions (.pem, .key, .p12, .pfx, .jks, .keystore) - Add .dist safe suffix; smart .env matching (excludes .envrc, .environment) - Directory-level blocking for .aws/, .docker/, .kube/ (not just specific files) - Trailing-slash matching so bare directory paths trigger detection Shell tool hardening: - Strip surrounding quotes from tokens before sensitive path check - Add grep, awk, sed to FILE_READ_COMMANDS - Scan ALL redirect operators in a segment, not just the first Other fixes: - Add trailing \b to Telegram bot token regex to prevent over-matching - Update error messages to reference secret_list/secret_create - Strengthen ListDirTool test with tempfile-based .ssh directory Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(safety): close 4 adversarial bypass vectors in leak detector - Fix .env suffix check: use exact remainder matching instead of ends_with, so .env.production.dist is no longer allowed through - Detect process substitution <(...) in redirect checks and scan inner tokens for sensitive paths - Add missing /id_rsa to SENSITIVE_PATH_PATTERNS (other SSH key types were already present) - Check --flag=value tokens for sensitive paths instead of skipping all tokens starting with - Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fix 3 items from zmanian re-review on leak detector 1. Document blocking canonicalize() in async context: added comment explaining the trade-off (sub-ms on local FS, could block on NFS) with guidance to make async if needed. 2. Fix overly broad standalone key patterns: moved id_rsa, id_ed25519, id_ecdsa, id_dsa, authorized_keys, known_hosts from substring-based SENSITIVE_PATH_PATTERNS to exact filename matching via SENSITIVE_FILENAMES. This prevents false positives on paths like /project/grid_rsa_data while still blocking /project/test_fixtures/id_rsa. 3. Remove duplicate is_sensitive_path unit tests from file.rs: these belong in sensitive_paths.rs which already has comprehensive coverage. Kept integration-level tests that exercise tool execute() methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: j-bloggs <j-bloggs@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Summary
Change Type
Linked Issue
Addresses review feedback from zmanian, gemini-code-assist, and copilot on this PR.
Validation
Security Impact
Database Impact
None
Blast Radius
Rollback Plan
Revert to staging (no sensitive path blocking). Credential patterns are additive and safe to keep.
Review Track
Track C - security changes in crates/ironclaw_safety/ and src/tools/builtin/
Feature Parity
No FEATURE_PARITY.md changes needed.