Back to skill

Security audit

LYGO Guardian P0 Stack

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a disclosed lightweight text-safety gate, but its optional bridge can execute an unverified Python file chosen through LYGO_STACK_ROOT.

Review before installing. Use the bundled validator only as a lightweight heuristic, not proof that another skill is safe. Do not set LYGO_STACK_ROOT unless you fully trust the exact local lygo-protocol-stack checkout and its lygo_p0_gate.py file; prefer a pinned installer version instead of @latest where possible.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/run_byte_gate.py:17
Finding

Environment-Controlled Execution of an Unverified Python Gate

Content
View full analysis

Vulnerability Details

File Location: scripts/run_byte_gate.py:17-26
Vulnerability Type: Unverified external code execution through an environment-controlled path
Risk Level: High

Vulnerable Code

python
def stack_gate(path: Path) -> int:
    stack = os.environ.get("LYGO_STACK_ROOT", "").strip()
    if not stack:
        return -1
    gate = Path(stack) / ".grok" / "skills" / "lygo-protocol-stack-operator" / "scripts" / "lygo_p0_gate.py"
    if not gate.is_file():
        gate = Path(stack) / "clawhub" / "mirrors" / "lygo-protocol-stack-operator" / "scripts" / "lygo_p0_gate.py"
    if not gate.is_file():
        return -1
    return subprocess.call([sys.executable, str(gate), str(path)])

Technical Analysis

The script obtains LYGO_STACK_ROOT from the process environment and constructs one of two expected paths beneath it. If a regular file exists at either location, the file is executed with the current Python interpreter.

The existence checks do not establish that the selected file belongs to the expected project or is trustworthy. The code does not validate the resolved root against an approved path, check ownership or permissions, verify a cryptographic hash or signature, or require confirmation before executing the discovered script.

Using an argument array prevents shell-metacharacter injection, but it does not address executable substitution: an attacker who can influence the environment and populate the expected directory structure can select arbitrary Python code for execution.

Attack Path

  1. An attacker gains control over the LYGO_STACK_ROOT environment value or causes the command to run in an environment containing an attacker-selected value.
  2. The attacker creates either expected nested path beneath that root:
    • .grok/skills/lygo-protocol-stack-operator/scripts/lygo_p0_gate.py, or
    • clawhub/mirrors/lygo-protocol-stack-operator/scripts/lygo_p0_gate.py.
  3. The attacker places arbitrary Python code ...[truncated 920 chars]
Remediation
View remediation

Remediation Suggestions

  1. Do not discover executable code solely through an environment variable. Prefer a pinned, packaged implementation imported through the normal dependency mechanism.
  2. Require the external integration to be explicitly enabled and display the fully resolved executable path before running it.
  3. Resolve the path with Path.resolve() and ensure it is beneath a user-approved canonical root.
  4. Verify the external file using a pinned cryptographic digest or a trusted digital signature before execution.
  5. Validate file ownership and reject files or parent directories writable by untrusted users.
  6. Consider running the external gate in a sandbox with minimal filesystem, environment, and network access.
  7. Fail closed with a clear review-required result if authenticity cannot be established; do not silently treat path existence as proof of identity.
  8. Add tests proving that arbitrary roots and modified gate files are rejected.

T08 · Insecure Dependencies

Warning
Location
SKILL.md:17
Finding

Unpinned Mutable Package Executed Through npx

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:17
Vulnerability Type: Mutable third-party installer dependency
Risk Level: Medium

Vulnerable Code

bash
npx clawhub@latest install deepseekoracle/lygo-guardian-p0-stack

Technical Analysis

The documented installation command instructs users to retrieve and execute the package identified by the mutable latest tag. The audited project does not pin an exact clawhub version or provide an integrity hash, lockfile, signature requirement, or verification procedure for the executable package retrieved by npx.

Consequently, the behavior of the installation command can change after this project has been reviewed. This creates a supply-chain trust boundary that is not represented by the bundled source code.

This finding does not establish that the current clawhub package is malicious. The vulnerability is the unsafe reliance on a mutable, remotely supplied executable without reproducible version or integrity controls.

Attack Path

  1. The package represented by clawhub@latest, its registry account, its publication pipeline, or its mutable tag is compromised or changed unexpectedly.
  2. A user follows the installation instruction in SKILL.md.
  3. npx retrieves the then-current package rather than a version reviewed alongside this project.
  4. Package installation or runtime logic executes on the user's system.
  5. A compromised release performs actions with the privileges available to the invoking user.

Impact Assessment

A malicious dependency release could execute code under the invoking user's account during the documented installation flow. Potential scope includes access to readable files, environment variables, project data, package-manager credentials, and other resources available to that account.

The actual impact depends on the external package's behavior and the privileges used to run npx; no malicious dependency payload is included in the audited repository ...[truncated 7 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace @latest with an exact, audited package version.
  2. Provide an integrity digest or signature and require users to verify it before execution.
  3. Publish a lockfile or equivalent reproducible dependency metadata where applicable.
  4. Document the trust boundary and warn that npx retrieves and executes third-party code.
  5. Prefer an installation mechanism that separates download and inspection from execution.
  6. Establish a controlled update process in which new versions are reviewed before the pinned version is changed.

T09 · Insecure Skill Coding Practices

Warning
Location
src/guardian/p0_4_gate.py:5
Finding

Security Gate Can Approve Malicious Skills Due to Narrow and Case-Inconsistent Matching

Content
View full analysis

Vulnerability Details

File Location: src/guardian/p0_4_gate.py:5-9, 12-35
Vulnerability Type: Bypassable security validation and unsafe approval semantics
Risk Level: Medium

Vulnerable Code

python
HARD_BLOCK_PATTERNS = {
    "self_harm": re.compile(r"(kill myself|end my life|suicide)", re.I),
    "violence": re.compile(r"(kill them|murder|bomb|shoot)", re.I),
    "keys_theft": re.compile(r"(private key|seed phrase|password)"),
}


def p0_4_validate(content: str, context: dict) -> dict:
    text = content or ""
    lowered = text.lower()
    for name, pattern in HARD_BLOCK_PATTERNS.items():
        if pattern.search(text):
            return {
                "deterministic_result": False,
                "score": 1.0,
                "pattern_name": name,
                "details": {"reason": f"matched hard pattern: {name}"},
            }
    score = 0.0
    pattern_name = "none"
    if any(w in lowered for w in ["hate", "worthless", "idiot", "stupid"]):
        score = max(score, 0.5)
        pattern_name = "hostility"
    if "trust me" in lowered and "secret" in lowered:
        score = max(score, 0.6)
        pattern_name = "manipulation_risk"
    return {
        "deterministic_result": True,
        "score": float(score),
        "pattern_name": pattern_name,
        "details": {},
    }

The documentation recommends applying this gate to unknown skills:

markdown
- After installing **unknown ClawHub skills** — run `scripts/run_byte_gate.py` on `SKILL.md`.

Technical Analysis

The credential-related expression is compiled without re.I, unlike the self-harm and violence expressions. Therefore, capitalization variants such as PASSWORD, Private Key, and Seed Phrase do not match that hard-block rule.

More broadly, the validator is an allow-by-default keyword filter. Text that does not contain its small set of literal phrases receives a zero gate score, even if it contains dangerous Skill behavior such as comma ...[truncated 1831 chars]

Remediation
View remediation

Remediation Suggestions

  1. Compile every intended case-insensitive pattern consistently, including the credential-related expression.
  2. Use token-aware or boundary-aware matching to reduce both bypasses and accidental substring matches.
  3. Add tests for capitalization, spacing, punctuation, Unicode confusables, encoding, and paraphrased dangerous instructions.
  4. Add detection for Skill-specific attack primitives, including command execution, remote downloads, persistence, secret access, dynamic evaluation, and instruction hijacking.
  5. Replace allow-by-default behavior for unknown third-party Skills with an unknown or manual_review_required result.
  6. Reserve allow for inputs that have passed a clearly defined and sufficiently comprehensive policy.
  7. Make the CLI distinguish “no known pattern detected” from “verified safe,” including distinct output and exit codes.
  8. Strengthen the documentation to state prominently that a passing heuristic result is not a security approval and cannot replace source review.
  9. Add adversarial fixtures and regression tests for realistic malicious Skill files that avoid obvious keywords.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (10)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The skill description claims broader guardian, bridge, and protocol-stack integration behavior than is evidenced by the provided content, which creates a trust and review gap. In security tooling, overstating protections or integrations is dangerous because operators may rely on controls that are not actually implemented, leading to false assurance and missed malicious content.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 38)May include surrounding context.

md
- After installing **unknown ClawHub skills** — run `scripts/run_byte_gate.py` on `SKILL.md`.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill advertises or implies capabilities involving environment variables, file access, network installation, and shell execution, but does not declare an explicit tool/permission scope. In agent ecosystems, missing scope declarations can cause overbroad execution privileges or make reviewers underestimate what the skill may invoke, increasing the chance of unsafe file reads, package installs, or command execution.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
91% confidence
Finding

The install instruction uses npx clawhub@latest, which pulls an unpinned, moving version of a remotely fetched package. If the upstream package is compromised or changes behavior, users may execute unexpected code during installation, creating a supply-chain risk with direct shell execution impact.

Content

No source excerpt is available for this finding.

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill explicitly launches an external Python script from a location controlled by LYGO_STACK_ROOT, which creates an execution boundary crossed with untrusted path input. In the context of an agent skill, this is more dangerous because skills often run in automation pipelines or privileged developer environments where environment manipulation can lead to immediate arbitrary code execution.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The script executes another Python file via subprocess, and the target path is derived from LYGO_STACK_ROOT, an environment variable that can be externally influenced. Although subprocess is invoked without shell=True, this still enables arbitrary code execution if an attacker can set LYGO_STACK_ROOT to a directory containing a malicious lygo_p0_gate.py at the expected path.

Content

Scanner excerpt · scripts/run_byte_gate.py (reported line 26)May include surrounding context.

python
gate = Path(stack) / "clawhub" / "mirrors" / "lygo-protocol-stack-operator" / "scripts" / "lygo_p0_gate.py"
    if not gate.is_file():
        return -1
    return subprocess.call([sys.executable, str(gate), str(path)])


def text_gate(content: str) -> dict:

Tainted flow: 'gate' from os.environ.get (line 23, credential/environment) → subprocess.call (code execution)

Medium
Category
Data Flow
Confidence
98% confidence
Finding

There is a direct tainted flow from os.environ.get("LYGO_STACK_ROOT") into construction of the executed script path, culminating in subprocess.call. An attacker who controls the environment can redirect execution to attacker-supplied code, making this a genuine code-execution risk rather than a mere configuration issue.

Content

Scanner excerpt · scripts/run_byte_gate.py (reported line 26)May include surrounding context.

python
gate = Path(stack) / "clawhub" / "mirrors" / "lygo-protocol-stack-operator" / "scripts" / "lygo_p0_gate.py"
    if not gate.is_file():
        return -1
    return subprocess.call([sys.executable, str(gate), str(path)])


def text_gate(content: str) -> dict:

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.