Skip to content

Conversation

@Rene-Kuhm
Copy link

@Rene-Kuhm Rene-Kuhm commented Jan 5, 2026

Pull Request: Enterprise Security Hooks

Summary

Add comprehensive enterprise security hooks for GDPR, SOC2, HIPAA, and PCI DSS compliance in OpenCode.

This PR introduces a new enterprise-security hook that provides:

  • File Protection: Blocks access to sensitive files (.env, SSH keys, secrets, API keys)
  • Compliance Checks: Detects PII, hardcoded credentials, and insecure logging patterns
  • Bash Validation: Blocks dangerous bash commands (rm -rf /, fork bombs, disk wipes)

Motivation

Enterprise users need built-in security controls to prevent accidental exposure of:

  • Environment variables and secrets
  • Personally Identifiable Information (PII)
  • Hardcoded credentials (API keys, passwords, tokens)
  • Dangerous system commands

This hook helps organizations meet compliance requirements for GDPR, SOC2, HIPAA, and PCI DSS.

Implementation Details

New Files

src/hooks/enterprise-security/
├── index.ts          # Main hook implementation
├── constants.ts      # Protected patterns (files, PII, credentials, bash)
├── types.ts          # TypeScript types
├── utils.ts          # Validation utilities
└── AGENTS.md         # Complete documentation

Hook Integration

  • tool.execute.before: Validates file access, content compliance, bash commands (blocking)
  • tool.execute.after: Scans tool output for sensitive data (warning only)

Configuration

Users can disable the hook via:

{
  "disabled_hooks": ["enterprise-security"]
}

Protected Patterns

Files (glob patterns):

  • Environment files: .env, .env.*, *.env
  • SSH keys: .ssh/*, *.pem, *.key, *_rsa
  • Secrets: secrets/*, .secrets/*, credentials.json
  • Cloud credentials: .aws/*, gcp-credentials.json, firebase-adminsdk*.json
  • Terraform state: *.tfstate, terraform.tfvars
  • API keys: api-keys.*, .npmrc, .docker/config.json

PII Patterns (regex):

  • Social Security Numbers (SSN)
  • Credit card numbers
  • Phone numbers
  • Email addresses with passwords

Hardcoded Credentials (regex):

  • API keys: api_key = "..."
  • Passwords: password = "..."
  • Tokens: token = "..."
  • AWS keys: AKIA[0-9A-Z]{16}

Dangerous Bash (regex):

  • rm -rf / (except /tmp)
  • Fork bombs
  • Disk wipe commands
  • Filesystem formatting
  • curl | bash / wget | sh

Compliance Standards

Helps meet requirements for:

  • GDPR: PII detection and protection
  • SOC2: Access control and audit logging
  • HIPAA: PHI (Protected Health Information) protection
  • PCI DSS: Credit card data protection

Testing

  • ✅ TypeScript: Zero type errors
  • ✅ Build: Successful (bun run build)
  • ✅ Linter: Clean (Biome)
  • ✅ Schema: Auto-generated with new hook name

Examples

Example 1: Protected File Blocked

// Attempt to read .env file
Read({ filePath: ".env" })

// Result: BLOCKED
// Message: "SECURITY: Access to protected file denied.
// File: .env
// Reason: Pattern match: .env"

Example 2: Hardcoded Credential Blocked

// Attempt to write hardcoded password
Write({
  filePath: "config.ts",
  content: 'const password = "mySecretPassword123"'
})

// Result: BLOCKED
// Message: "COMPLIANCE WARNING: Potential security issues detected.
// ERRORS (must fix):
//   - Hardcoded Credential: password\\s*=\\s*[\"'][^\"']{4,}[\"']"

Example 3: Dangerous Bash Blocked

// Attempt to run rm -rf /
Bash({ command: "rm -rf /" })

// Result: BLOCKED
// Message: "SECURITY: Dangerous bash command blocked.
// Command: rm -rf /
// Reason: Dangerous command pattern detected"

Documentation

Complete documentation available in src/hooks/enterprise-security/AGENTS.md including:

  • Feature descriptions
  • Usage examples
  • Configuration options
  • Compliance standards
  • FAQ

Breaking Changes

None. This is a new opt-in hook (enabled by default but can be disabled).

Checklist

  • Code follows project conventions (bun, TypeScript strict, kebab-case)
  • bun run typecheck passes
  • bun run build succeeds
  • No version changes in package.json
  • Documentation updated (AGENTS.md)
  • Hook registered in src/hooks/index.ts
  • Hook integrated in src/index.ts
  • Hook name added to HookNameSchema in src/config/schema.ts
  • JSON schema auto-generated with new hook

Related Issues

Closes: N/A (proactive enhancement for enterprise users)

Contributors


Note: This contribution is based on existing security patterns from my personal Claude Code configuration, now adapted for OhMyOpenCode to benefit the community.


Summary by cubic

Adds an enterprise security hook that protects sensitive files, detects PII and hardcoded credentials, and blocks dangerous bash commands to help meet GDPR, SOC2, HIPAA, and PCI DSS. This reduces secret leaks and unsafe operations by blocking risky actions and warning on potential exposure.

  • New Features
    • Blocks access to sensitive files (.env, SSH keys, secrets, Terraform state) via glob patterns.
    • Scans content for PII, credentials, and insecure logging; blocks errors, warns on risks.
    • Prevents dangerous bash (rm -rf /, fork bombs, disk wipes, curl|bash).
    • Integrated into tool.execute.before (blocking) and tool.execute.after (output warnings).
    • Configurable via disabled_hooks; enabled by default. Documentation in AGENTS.md.
    • Hook registered and added to schema and hook index.

Written for commit 631563e. Summary will update on new commits.

Add comprehensive enterprise security hook for GDPR/SOC2/HIPAA compliance.

Features:
- File Protection: Blocks access to sensitive files (.env, SSH keys, secrets)
- Compliance Check: Detects PII, hardcoded credentials, insecure logging
- Bash Validation: Blocks dangerous bash commands
- Configurable via disabled_hooks

Implements createEnterpriseSecurityHook() with full documentation.
@github-actions
Copy link
Contributor

github-actions bot commented Jan 5, 2026

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA).

To sign the CLA, please comment on this PR with:

I have read the CLA Document and I hereby sign the CLA

This is a one-time requirement. Once signed, all your future contributions will be automatically accepted.


I have read the CLA Document and I hereby sign the CLA


Rene seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@greptile-apps
Copy link

greptile-apps bot commented Jan 5, 2026

Greptile Summary

Adds comprehensive enterprise security hook that protects sensitive files (.env, SSH keys, credentials), detects PII and hardcoded credentials, and blocks dangerous bash commands to support GDPR/SOC2/HIPAA/PCI DSS compliance.

Major Changes:

  • New enterprise-security hook with tool.execute.before (blocking) and tool.execute.after (warnings) handlers
  • File protection using glob patterns via minimatch (.env, .ssh/*, *.pem, AWS/GCP credentials, Terraform state)
  • Content scanning for PII (SSN, credit cards, emails with passwords), hardcoded credentials (API keys, passwords, tokens), and insecure logging
  • Bash command validation blocking destructive operations (rm -rf /, fork bombs, disk wipes, curl|bash)
  • Allowed paths for Claude Code and OpenCode configs (.claude/*, .config/opencode/*)
  • Properly integrated into hook system with conditional enable/disable support

Issues Found:

  • IP address pattern in PII detection will cause false positives for localhost/common IPs in code
  • Phone number pattern too broad, matches non-phone sequences
  • Dangerous bash regex for rm -rf / doesn't catch paths like /home/tmp
  • console.warn usage may not be visible in non-interactive contexts

Confidence Score: 4/5

  • This PR is safe to merge with minor improvements recommended
  • The implementation is well-structured and properly integrated into the hook system with comprehensive documentation. The core security mechanisms are sound - file protection, credential detection, and bash validation work correctly. However, there's one logic issue with the rm -rf pattern that could miss dangerous commands, and several style improvements around false positives in PII/phone detection and console.warn visibility. These issues don't break functionality but should be addressed for production use
  • Pay close attention to src/hooks/enterprise-security/constants.ts for regex pattern improvements (lines 99, 101, 127)

Important Files Changed

Filename Overview
src/hooks/enterprise-security/index.ts Main hook implementation with tool.execute.before/after handlers; properly blocks dangerous operations but uses console.warn which may not be visible in all contexts
src/hooks/enterprise-security/constants.ts Security patterns and regexes; IP address pattern in PII_PATTERNS may cause false positives for legitimate code, phone pattern too broad
src/hooks/enterprise-security/utils.ts Path validation and pattern matching logic; uses minimatch correctly with multiple pattern checks for comprehensive coverage

Sequence Diagram

sequenceDiagram
    participant User
    participant OpenCode
    participant EnterpriseSecurityHook
    participant Utils
    participant ToolExecutor

    User->>OpenCode: Execute tool (Read/Write/Edit/Bash)
    OpenCode->>EnterpriseSecurityHook: tool.execute.before(input, output)
    
    alt Tool is Read/Write/Edit
        EnterpriseSecurityHook->>Utils: isProtectedFile(filePath)
        Utils-->>EnterpriseSecurityHook: {blocked: true/false, reason}
        alt File is protected
            EnterpriseSecurityHook->>OpenCode: Set blocked=true, message
            OpenCode-->>User: SECURITY: Access denied
        end
    end
    
    alt Tool is Write/Edit
        EnterpriseSecurityHook->>Utils: checkComplianceViolations(content)
        Utils-->>EnterpriseSecurityHook: violations[]
        alt Has error violations (hardcoded credentials)
            EnterpriseSecurityHook->>OpenCode: Set blocked=true, message
            OpenCode-->>User: COMPLIANCE WARNING: Errors detected
        else Has warning violations (PII)
            EnterpriseSecurityHook->>EnterpriseSecurityHook: console.warn()
        end
    end
    
    alt Tool is Bash
        EnterpriseSecurityHook->>Utils: checkDangerousBashCommand(command)
        Utils-->>EnterpriseSecurityHook: {dangerous: true/false, reason}
        alt Command is dangerous
            EnterpriseSecurityHook->>OpenCode: Set blocked=true, message
            OpenCode-->>User: SECURITY: Dangerous command blocked
        end
    end
    
    alt Not blocked
        OpenCode->>ToolExecutor: Execute tool
        ToolExecutor-->>OpenCode: output
        OpenCode->>EnterpriseSecurityHook: tool.execute.after(input, output)
        EnterpriseSecurityHook->>Utils: checkComplianceViolations(output.output)
        Utils-->>EnterpriseSecurityHook: violations[]
        alt Has warning violations
            EnterpriseSecurityHook->>EnterpriseSecurityHook: console.warn()
        end
        OpenCode-->>User: Return output
    end
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (4)

  1. src/hooks/enterprise-security/constants.ts, line 101 (link)

    style: IP addresses in code (e.g., 127.0.0.1, 0.0.0.0) will trigger false PII warnings. Consider removing this pattern or adding context checking (e.g., only flag if associated with user data keywords)

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  2. src/hooks/enterprise-security/constants.ts, line 99 (link)

    style: Phone pattern \b\(?\d{3}\)?[-. ]?\d{3}[-. ]?\d{4}\b will match many non-phone number sequences (e.g., version numbers like (123) 456-7890 format timestamps). This may cause excessive false positive warnings

  3. src/hooks/enterprise-security/index.ts, line 86-87 (link)

    style: console.warn may not be visible to users in non-interactive environments or when OpenCode redirects output. Consider using the plugin's notification system or adding warnings to the tool output message

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  4. src/hooks/enterprise-security/constants.ts, line 127 (link)

    logic: Regex /rm\s+-rf\s+\/(?!tmp|var\/tmp)/i uses negative lookahead correctly but will still match rm -rf /home/tmp (which is dangerous). The pattern only checks the immediate next path component. Consider more comprehensive validation or exact path matching

9 files reviewed, 4 comments

Edit Code Review Agent Settings | Greptile

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

5 issues found across 9 files

Confidence score: 2/5

  • Multiple high-severity security gaps remain in src/hooks/enterprise-security/constants.ts, including incomplete rm flag coverage and missing curl|sh/wget|bash protections, so the PR currently exposes command-execution bypasses.
  • normalizePath() and allowlist checks in src/hooks/enterprise-security/utils.ts are vulnerable to traversal and substring bypasses, making it likely that .env and other sensitive files can be accessed despite intended safeguards.
  • Lack of try/catch in src/hooks/enterprise-security/index.ts hook functions risks crashing sessions, which contradicts the documented guidance and could impact users immediately.
  • Pay close attention to src/hooks/enterprise-security/constants.ts, src/hooks/enterprise-security/utils.ts, src/hooks/enterprise-security/index.ts - address the identified security gaps and missing error handling before merging.
Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="src/hooks/enterprise-security/constants.ts">

<violation number="1" location="src/hooks/enterprise-security/constants.ts:127">
P1: Security gap: Pattern only catches `rm -rf` but not equivalent `rm -fr`. The flags `-rf` and `-fr` are interchangeable in the `rm` command, allowing `rm -fr /` to bypass this protection.</violation>

<violation number="2" location="src/hooks/enterprise-security/constants.ts:133">
P1: Security gap: `curl | sh` and `wget | bash` are not blocked. The patterns inconsistently check for different shells - curl only blocks piping to `bash` while wget only blocks piping to `sh`. Both tools can use either shell for remote code execution.</violation>
</file>

<file name="src/hooks/enterprise-security/index.ts">

<violation number="1" location="src/hooks/enterprise-security/index.ts:18">
P1: Hook functions lack error handling which could crash the session. The hooks documentation explicitly warns against this anti-pattern: &quot;Missing try/catch (don&#39;t crash session)&quot;. Wrap the function body in try/catch to prevent crashes from unexpected input or utility function failures.</violation>
</file>

<file name="src/hooks/enterprise-security/utils.ts">

<violation number="1" location="src/hooks/enterprise-security/utils.ts:23">
P1: Path traversal bypass: `normalizePath()` doesn&#39;t resolve `..` components. A path like `safe/../.env` bypasses the `.env` protection check but accesses the actual `.env` file when read by the filesystem. Use `path.normalize()` to properly resolve path components.</violation>

<violation number="2" location="src/hooks/enterprise-security/utils.ts:32">
P1: Security bypass: `includes()` allows any path containing an allowed substring to pass the allowlist. For example, `malicious.opencode/.env` would be allowed because it contains `.opencode/`. Use proper path prefix/suffix checking or segment-based matching instead of substring matching.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.


// Dangerous bash commands
export const DANGEROUS_BASH_PATTERNS = [
/rm\s+-rf\s+\/(?!tmp|var\/tmp)/i, // rm -rf / (except /tmp)
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 5, 2026

Choose a reason for hiding this comment

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

P1: Security gap: Pattern only catches rm -rf but not equivalent rm -fr. The flags -rf and -fr are interchangeable in the rm command, allowing rm -fr / to bypass this protection.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/enterprise-security/constants.ts, line 127:

<comment>Security gap: Pattern only catches `rm -rf` but not equivalent `rm -fr`. The flags `-rf` and `-fr` are interchangeable in the `rm` command, allowing `rm -fr /` to bypass this protection.</comment>

<file context>
@@ -0,0 +1,135 @@
+
+// Dangerous bash commands
+export const DANGEROUS_BASH_PATTERNS = [
+	/rm\s+-rf\s+\/(?!tmp|var\/tmp)/i, // rm -rf / (except /tmp)
+	/:\(\)\{\s*:\|:&amp;\s*\};:/, // Fork bomb
+	/dd\s+if=\/dev\/zero/i, // Disk wipe
</file context>
Fix with Cubic

/mkfs\./i, // Format filesystem
/> \/dev\/sd[a-z]/i, // Direct disk write
/chmod\s+-R\s+777\s+\//i, // Chmod 777 on root
/curl.*\|\s*bash/i, // Curl | bash (potential security risk)
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 5, 2026

Choose a reason for hiding this comment

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

P1: Security gap: curl | sh and wget | bash are not blocked. The patterns inconsistently check for different shells - curl only blocks piping to bash while wget only blocks piping to sh. Both tools can use either shell for remote code execution.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/enterprise-security/constants.ts, line 133:

<comment>Security gap: `curl | sh` and `wget | bash` are not blocked. The patterns inconsistently check for different shells - curl only blocks piping to `bash` while wget only blocks piping to `sh`. Both tools can use either shell for remote code execution.</comment>

<file context>
@@ -0,0 +1,135 @@
+	/mkfs\./i, // Format filesystem
+	/&gt; \/dev\/sd[a-z]/i, // Direct disk write
+	/chmod\s+-R\s+777\s+\//i, // Chmod 777 on root
+	/curl.*\|\s*bash/i, // Curl | bash (potential security risk)
+	/wget.*\|\s*sh/i, // Wget | sh (potential security risk)
+];
</file context>
Fix with Cubic

} from "./utils";

export function createEnterpriseSecurityHook(_ctx: PluginInput) {
const toolExecuteBefore = async (
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 5, 2026

Choose a reason for hiding this comment

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

P1: Hook functions lack error handling which could crash the session. The hooks documentation explicitly warns against this anti-pattern: "Missing try/catch (don't crash session)". Wrap the function body in try/catch to prevent crashes from unexpected input or utility function failures.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/enterprise-security/index.ts, line 18:

<comment>Hook functions lack error handling which could crash the session. The hooks documentation explicitly warns against this anti-pattern: &quot;Missing try/catch (don&#39;t crash session)&quot;. Wrap the function body in try/catch to prevent crashes from unexpected input or utility function failures.</comment>

<file context>
@@ -0,0 +1,152 @@
+} from &quot;./utils&quot;;
+
+export function createEnterpriseSecurityHook(_ctx: PluginInput) {
+	const toolExecuteBefore = async (
+		input: ToolExecuteInput,
+		output: ToolExecuteBeforeOutput,
</file context>
Fix with Cubic

const allowedNormalized = normalizePath(allowed);
if (
normalized.endsWith(allowedNormalized) ||
normalized.includes(allowedNormalized)
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 5, 2026

Choose a reason for hiding this comment

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

P1: Security bypass: includes() allows any path containing an allowed substring to pass the allowlist. For example, malicious.opencode/.env would be allowed because it contains .opencode/. Use proper path prefix/suffix checking or segment-based matching instead of substring matching.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/enterprise-security/utils.ts, line 32:

<comment>Security bypass: `includes()` allows any path containing an allowed substring to pass the allowlist. For example, `malicious.opencode/.env` would be allowed because it contains `.opencode/`. Use proper path prefix/suffix checking or segment-based matching instead of substring matching.</comment>

<file context>
@@ -0,0 +1,134 @@
+		const allowedNormalized = normalizePath(allowed);
+		if (
+			normalized.endsWith(allowedNormalized) ||
+			normalized.includes(allowedNormalized)
+		) {
+			return true;
</file context>
Fix with Cubic

if (normalized.startsWith("./")) {
normalized = normalized.slice(2);
}
return normalized;
Copy link

@cubic-dev-ai cubic-dev-ai bot Jan 5, 2026

Choose a reason for hiding this comment

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

P1: Path traversal bypass: normalizePath() doesn't resolve .. components. A path like safe/../.env bypasses the .env protection check but accesses the actual .env file when read by the filesystem. Use path.normalize() to properly resolve path components.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/hooks/enterprise-security/utils.ts, line 23:

<comment>Path traversal bypass: `normalizePath()` doesn&#39;t resolve `..` components. A path like `safe/../.env` bypasses the `.env` protection check but accesses the actual `.env` file when read by the filesystem. Use `path.normalize()` to properly resolve path components.</comment>

<file context>
@@ -0,0 +1,134 @@
+	if (normalized.startsWith(&quot;./&quot;)) {
+		normalized = normalized.slice(2);
+	}
+	return normalized;
+}
+
</file context>
Fix with Cubic

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant