Skip to content

fix(opencode): harden secret-read regex patterns#3295

Open
Peldan wants to merge 4 commits into
microsoft:mainfrom
Peldan:fix/opencode-secret-read-bypass
Open

fix(opencode): harden secret-read regex patterns#3295
Peldan wants to merge 4 commits into
microsoft:mainfrom
Peldan:fix/opencode-secret-read-bypass

Conversation

@Peldan

@Peldan Peldan commented Jul 8, 2026

Copy link
Copy Markdown

Description

The secret-read blocked-command rule matched an allow-list of reader binaries (cat/less/more/head/tail/sed/awk), so equivalent credential reads via copy/encode/dump utilities (cp, xxd, base64, dd, strings, tee, grep, ...) and shell input redirection (< .env, source .env) fell through to the review path and executed. The env-dump pattern missed env >, declare -x, and export -p, and the /proc environ path rule matched only numeric PIDs, so e.g. /proc/self/environ and /proc/thread-self/environ (a full dump of the agent's environment) escaped both the bash rule and the direct-resource path rule.

Broaden the reader/redirect/env-dump patterns to key on the sensitive target rather than a reader allow-list, and extend the environ path pattern to self/thread-self. Precision is preserved for common legitimate commands: the .env template allow-list still applies, a copy's write destination is not treated as a read (cp .env.example .env), declare -x VAR=val (exporting a variable) is distinguished from a bare declare -x dump, and env/set are anchored to a command position so an incidental .env> in a string is not matched. Adds regression tests for both the closed bypasses and the preserved cases.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Security fix

Package(s) Affected

  • agent-governance

Checklist

  • My code follows the project style guidelines (ruff check)
  • I have added tests that prove my fix/feature works
  • All new and existing tests pass (pytest)
  • I have updated documentation as needed
  • I have signed the Microsoft CLA

Attribution & Prior Art

  • This contribution does not contain code copied or derived from other projects without attribution
  • Any external projects that inspired this design are credited in code comments or documentation
  • If this PR implements functionality similar to an existing open-source project, I have listed it below

AI Assistance

  • I can explain every meaningful change in this PR: what it does, why, and what tradeoffs were considered
  • I have run tests and verification appropriate for this change
  • No part of this PR was autonomously submitted by an AI agent without my review
  • I have not used AI to generate review comments on others' PRs

If AI tools materially shaped this change, briefly note what was used:
Claude used for drafting the fix, and write the commit message. All changes reviewed.

IP, Patents, and Licensing

  • This contribution does not implement patent-pending or patent-encumbered techniques
  • This contribution does not require an NDA or licensing agreement to understand or use
  • Any AI tools used have terms compatible with the MIT License

Related Issues

The secret-read blocked-command rule matched an allow-list of reader
binaries (cat/less/more/head/tail/sed/awk), so equivalent credential
reads via copy/encode/dump utilities (cp, xxd, base64, dd, strings, tee,
grep, ...) and shell input redirection (`< .env`, `source .env`) fell
through to the review path and executed. The env-dump pattern likewise
missed `env >`, `declare -x`, and `export -p`, and the /proc environ
path rule matched only numeric PIDs — so `/proc/self/environ` and
`/proc/thread-self/environ` (a full dump of the agent's environment)
escaped both the bash rule and the direct-resource path rule.

Broaden the reader/redirect/env-dump patterns to key on the sensitive
target rather than a reader allow-list, and extend the environ path
pattern to self/thread-self. Precision is preserved for common
legitimate commands: the `.env` template allow-list still applies, a
copy's write destination is not treated as a read (`cp .env.example
.env`), `declare -x VAR=val` (exporting a variable) is distinguished
from a bare `declare -x` dump, and `env`/`set` are anchored to a command
position so an incidental `.env>` in a string is not matched. Adds
regression tests for both the closed bypasses and the preserved cases.
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown

PR Review Summary

Check Status Details
🔍 Code Review ⚠️ Missing No current-run comment
🛡️ Security Scan ⚠️ Missing No current-run comment
🔄 Breaking Changes ⚠️ Missing No current-run comment
📝 Docs Sync ⚠️ Missing No current-run comment
🧪 Test Coverage ⚠️ Missing No current-run comment

Verdict: ⚠️ AI review incomplete; ready for human review

AI review comments are untrusted advisory output. The summary reports workflow-generated completion status only, not model-authored pass/fail claims.

@github-actions github-actions Bot added the size/M Medium PR (< 200 lines) label Jul 8, 2026
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
🤖 AI Agent: contributor-guide — View details

AI-generated review output. Treat it as untrusted analysis and verify before acting.

Welcome, and thank you for your contribution! Great job on providing a detailed explanation of the changes and including comprehensive test coverage.

Before merging, please address the following:

  1. Update the documentation to reflect the changes in regex patterns and their expanded scope, as noted in your checklist.

For guidance, refer to CONTRIBUTING.md. Let us know if you need any help!

@Peldan
Peldan marked this pull request as ready for review July 8, 2026 09:13

@imran-siddique imran-siddique left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Anchoring the deny on the sensitive target rather than an allowlist of reader binaries is the right model, and the added coverage for encode/dump utilities, shell redirection, and /proc/self|thread-self/environ closes real gaps. The dropCopyDestinationToken handling, so cp .env.example .env scaffolding isn't misread as a sensitive-destination read, is a nice touch and the GNU -t case is tested. One framing note for future readers: a regex denylist is defense-in-depth, not a hard boundary, so let's keep treating it as best-effort.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
🤖 AI Agent: docs-sync-checker — Docs Sync

AI-generated review output. Treat it as untrusted analysis and verify before acting.

Docs Sync

  • README.md -- documentation does not reflect the updated regex patterns or the broadened scope of credential-read detection.
  • CHANGELOG.md -- missing entry for the changes to regex patterns and the addition of new test cases for credential-read detection.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
🤖 AI Agent: security-scanner — View details

AI-generated review output. Treat it as untrusted analysis and verify before acting.

No security issues found.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
🤖 AI Agent: test-generator — `agent-governance-opencode/lib/policy.mjs`

AI-generated review output. Treat it as untrusted analysis and verify before acting.

agent-governance-opencode/lib/policy.mjs

  • dropCopyDestinationToken -- Missing tests for edge cases where the -t or --target-directory option is malformed or combined with other arguments.
  • dropCopyDestinationToken -- Missing tests for scenarios where no valid path tokens are present after filtering.

agent-governance-opencode/config/default-policy.json

  • commandPatterns -- Missing tests for commands with mixed-case sensitive tokens (e.g., .ENV, Id_rSa) to validate case-insensitivity.
  • commandPatterns -- Missing tests for commands with unusual whitespace or separators (e.g., cat\t.env, cat;.env) to ensure robust pattern matching.

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
🤖 AI Agent: code-reviewer — Action Items:

AI-generated review output. Treat it as untrusted analysis and verify before acting.

TL;DR: 0 blockers, 1 warning. The PR improves security but requires additional documentation updates.

# Sev Issue Where
1 Warn Documentation updates are missing for the new regex patterns and logic changes. PR description checklist and code changes

Action Items:

  • None.

Warnings:

# Warning Fine as follow-up PR?
1 Update documentation to reflect the new regex patterns and logic changes for secret-read rules. Yes

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
🤖 AI Agent: breaking-change-detector — API Compatibility

AI-generated review output. Treat it as untrusted analysis and verify before acting.

API Compatibility

Severity Change Impact
High Modified regex patterns in default-policy.json to broaden the scope of denied commands and paths. Existing commands or paths that previously passed validation may now be denied, potentially breaking workflows.
High Updated isSafeEnvTemplateReadCommand function to exclude certain tokens from being classified as sensitive reads. May change the behavior of existing workflows that rely on the previous implementation.
High Added dropCopyDestinationToken function to modify token handling for copy/move commands. Could alter the behavior of existing workflows involving file operations.
High Modified evaluateDirectResourceAccess to include new logic for handling direct resource access. May impact existing functionality that depends on the previous implementation.

@Peldan

Peldan commented Jul 9, 2026

Copy link
Copy Markdown
Author

LGTM. Anchoring the deny on the sensitive target rather than an allowlist of reader binaries is the right model, and the added coverage for encode/dump utilities, shell redirection, and /proc/self|thread-self/environ closes real gaps. The dropCopyDestinationToken handling, so cp .env.example .env scaffolding isn't misread as a sensitive-destination read, is a nice touch and the GNU -t case is tested. One framing note for future readers: a regex denylist is defense-in-depth, not a hard boundary, so let's keep treating it as best-effort.

Agreed. Feels like a real issue having the regex become too bloated as well. The long-term direction could be a semantic command/resource classifier, perhaps an AST

@imran-siddique imran-siddique left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anchoring the deny on the sensitive target instead of a reader allow-list is the right model, the bypasses are closed, and the copy-destination and env/declare edge cases are handled and tested. No ReDoS or fail-open introduced.

@imran-siddique

Copy link
Copy Markdown
Collaborator

@MohammadHaroonAbuomar @liamcrumm gentle nudge: this PR has been awaiting a code-owner review for over 3 business days. Could one of you take a look when you have a moment? Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/M Medium PR (< 200 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants