Back to skill

Security audit

Nexus Brain

Security checks for vulnerabilities and agentic risk

Overview

This SRE skill is mostly coherent, but it needs Review because it can read operational logs, send them to an external AI tool, and support recovery actions with limited scoping and safeguards.

Review this before using it in production. Use a trusted, fixed opencode binary, pin dependencies, restrict which logs may be analyzed, require explicit approval for restarts or other recovery actions, and do not rely on the built-in regex redaction to protect secrets.

Vulnerability Patterns
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
bridge.py:6
Finding
Incomplete Redaction of Sensitive Data Before External AI Processing<![CDATA[ ## Vulnerability Details **File Location**: `bridge.py`, lines 6-13 and 25-27 **Vulnerability Type**: Incomplete sensitive-data redaction **Risk Level**: Medium ### Vulnerable Code ```python def redact_logs(text): """Simple regex to mask potential secrets in logs before AI analysis.""" patterns = [ (r'([Pp]assword|[Ss]ecret|[Tt]oken|[Aa]pi[Kk]ey)["\s:=]+[^\s,"]+', r'\1: [REDACTED]'), (r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', '[EMAIL_REDACTED]') ] for pattern, replacement in patterns: text = re.sub(pattern, replacement, text) return text ``` ```python # Sanitize prompt (basic) safe_prompt = redact_logs(prompt) res = subprocess.run([opencode_path, "run", safe_prompt], capture_output=True, text=True, timeout=60) ``` ### Technical Analysis The bridge relies on two regular expressions to sanitize potentially sensitive prompts before providing them to the configured `opencode` reasoning service. The secret expression only recognizes values preceded by the labels `password`, `secret`, `token`, or `apikey`, with limited case variations and separators. This approach does not cover many common secret representations, including: - `Authorization: Bearer <credential>` headers - Session cookies and cookie headers - Private keys and certificate material - Database connection strings containing credentials - Cloud-provider access keys - Provider-specific API key formats - Tokens whose labels contain hyphens or underscores - Multiline or whitespace-containing secrets - Unlabeled credentials appearing in log messages Consequently, the call to `redact_logs()` does not establish that the resulting prompt is safe to transmit. The documentation's broad claim that passwords, tokens, and related data are masked may also give operators a false sense of protection. ### Attack Path 1. A diagnostic prompt or log contains sensitive data in a format not recognized by the two redaction expressions. 2. The user passes t ...[truncated 1036 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the narrow label-based approach with layered secret detection covering authorization headers, cookies, private keys, connection strings, cloud credentials, and provider-specific token formats. 2. Prefer allowlist-based log selection so only fields explicitly approved for external analysis are transmitted. 3. Parse structured logs as structured data and remove sensitive fields by key rather than relying exclusively on regular expressions. 4. Detect and redact multiline secrets, including PEM-encoded private keys. 5. Require explicit operator consent before sending diagnostic content outside the local environment. 6. Clearly identify the destination provider and the categories of data that may be transmitted. 7. Add unit tests for bypass cases, including bearer tokens, database URLs, cookies, multiline secrets, mixed-case labels, and credentials containing spaces or punctuation. 8. Consider a local-only reasoning mode for environments where diagnostic data cannot leave the host. ]]>

T07 · Tool Hijacking and Spoofing

Warning
Location
bridge.py:17
Finding
PATH-Based Opencode Executable Hijacking<![CDATA[ ## Vulnerability Details **File Location**: `bridge.py`, lines 17-27 **Vulnerability Type**: Untrusted executable resolution through inherited `PATH` **Risk Level**: Medium ### Vulnerable Code ```python def ask_orchestrator(prompt, target_binary="opencode"): # First, try to find the binary in PATH, then fallback to user home opencode_path = subprocess.run(["which", target_binary], capture_output=True, text=True).stdout.strip() if not opencode_path: opencode_path = os.path.expanduser("~/.opencode/bin/opencode") if not os.path.exists(opencode_path): return f"Error: {target_binary} binary not found in PATH or ~/.opencode/bin/" try: # Sanitize prompt (basic) safe_prompt = redact_logs(prompt) res = subprocess.run([opencode_path, "run", safe_prompt], capture_output=True, text=True, timeout=60) ``` ### Technical Analysis The bridge resolves `opencode` by executing `which` with the inherited process environment and then trusts the first matching path. It does not validate the resolved executable's canonical location, owner, permissions, integrity, or provenance. Although the subprocess call correctly uses an argument array rather than a shell, that protection does not prevent executable substitution. If an attacker can influence `PATH` or place a malicious executable in an earlier searched directory, the bridge will execute that file as though it were the legitimate `opencode` client. The fallback path is also accepted based only on existence. The code does not verify that it is a regular executable file securely owned by the expected user. ### Attack Path 1. An attacker gains write access to a directory that precedes the legitimate `opencode` installation in the victim's `PATH`, or induces the skill to run with an attacker-controlled `PATH`. 2. The attacker creates a malicious executable named `opencode` in that directory. 3. The victim invokes `bridge.py`. 4. The `which opencode` lookup re ...[truncated 852 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Require an explicitly configured absolute path to the trusted `opencode` executable instead of resolving it through `PATH`. 2. Canonicalize the configured path with `os.path.realpath()` and verify that it remains within an approved installation directory. 3. Confirm that the target is a regular executable file and is owned by the expected user or system administrator. 4. Reject executables and parent directories writable by unauthorized users. 5. Where operationally practical, verify the executable against a trusted cryptographic hash or package signature. 6. Run the bridge with a minimal, controlled environment and a fixed `PATH`. 7. Do not use the external `which` command; if path lookup remains necessary, use `shutil.which()` followed by ownership, permission, and location validation. 8. Execute the external tool under the least-privileged account required for its intended operation. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:19
Finding
Unpinned Python Dependency Installation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, line 19; also declared without a version in `_meta.json`, line 10 **Vulnerability Type**: Uncontrolled third-party dependency version **Risk Level**: Low ### Vulnerable Code ```text 1. `pip install psutil` ``` The package metadata also omits a version constraint: ```json "pythonPackages": ["psutil"] ``` ### Technical Analysis The installation instructions request `psutil` without a pinned version or integrity hash. As a result, installations performed at different times may resolve to different package releases and are not reproducible. Installing Python packages can execute package build or installation logic. If the configured package source is compromised, incorrectly configured, or serves a malicious future release, the uncontrolled installation command can introduce unreviewed code into the environment. No evidence was found that the current `psutil` package is malicious. The finding concerns the project's failure to constrain and verify the dependency retrieved during future installations. ### Attack Path 1. An operator follows the documented `pip install psutil` instruction. 2. `pip` queries the operator's configured package index and resolves the latest acceptable release. 3. A compromised index, unsafe mirror, dependency-source misconfiguration, or malicious future release supplies unreviewed package content. 4. Package installation or build logic executes under the operator's account. 5. The installed dependency may then retain access through its installed files and execute whenever imported or otherwise invoked. ### Impact Assessment Potential impact is code execution with the privileges of the account performing the installation. If installation is performed globally or as an administrator, affected scope may include the system-wide Python environment and other applications using it. Under normal installation from a trusted package index, the more immediate risks are non-r ...[truncated 199 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin `psutil` to a reviewed, exact version in a dependency file. 2. Generate and verify cryptographic hashes, for example by using a hash-locked requirements file with `pip --require-hashes`. 3. Maintain a lock file or equivalent reproducible dependency manifest. 4. Retrieve packages only from an approved, authenticated package index. 5. Review and test dependency updates before changing the pinned version. 6. Perform installation in an isolated virtual environment rather than the system Python environment. 7. Add automated vulnerability and provenance checks for third-party dependencies. 8. Keep `_meta.json`, installation documentation, and the lock file synchronized so all installation paths enforce the same reviewed version. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (3)

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def ask_orchestrator(prompt, target_binary="opencode"):
    # First, try to find the binary in PATH, then fallback to user home
    opencode_path = subprocess.run(["which", target_binary], capture_output=True, text=True).stdout.strip()
    if not opencode_path:
        opencode_path = os.path.expanduser("~/.opencode/bin/opencode")
Confidence
95% confidence
Finding
The code resolves the target executable using PATH via `which`, allowing execution of whichever matching binary appears first in the environment. In attacker-controlled or untrusted environments, PATH hijacking can cause a malicious `opencode` binary to be selected and executed, leading to arbitrary code execution under the current user's privileges.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
try:
        # Sanitize prompt (basic)
        safe_prompt = redact_logs(prompt)
        res = subprocess.run([opencode_path, "run", safe_prompt], capture_output=True, text=True, timeout=60)
        return res.stdout if res.returncode == 0 else f"AI Error: {res.stderr}"
    except Exception as e:
        return f"Orchestrator Bridge Error: {str(e)}"
Confidence
90% confidence
Finding
The code passes user-controlled prompt content directly to an external executable, which creates a trust-boundary crossing and can leak sensitive input to another program for processing. Although shell injection is avoided by using an argument list, the external binary may log, retain, transmit, or misuse the prompt, and the in-code redaction is only partial and regex-based.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
Prompt content is sent to an external AI-related binary without any user-facing disclosure, creating a privacy and data-governance risk. Because prompts may contain credentials, internal data, or personal information, silent forwarding to another tool is dangerous, especially since the implemented redaction only covers a small subset of possible secrets.