Back to skill

Security audit

LYGO Agent Lattice (Layer E — Living Agent Network)

Security checks for vulnerabilities and agentic risk

Overview

The skill is not clearly malicious, but it delegates its core behavior to unbundled external Python tools selected from the environment without integrity checks.

Review before installing. Only use this skill with a trusted, local lygo-protocol-stack checkout, set LYGO_STACK_ROOT explicitly to that path, and avoid running it from directories where untrusted users can place a tools folder. Treat the advertised security controls as dependent on external code that was not included in this reviewed package.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T08 · Insecure Dependencies

Warning
Location
scripts/_stack_invoke.py:12
Finding
Execution of Unpinned and Unverified External Stack Tools<![CDATA[ ## Vulnerability Details **File Location**: `scripts/_stack_invoke.py`, lines 12–35 **Vulnerability Type**: Unverified external dependency execution **Risk Level**: Medium ### Vulnerable Code ```python def stack_root() -> Path: env = os.environ.get("LYGO_STACK_ROOT", "").strip() if env: return Path(env).resolve() for p in HERE.parents: if (p / "tools" / "agent_lattice_core.py").is_file(): return p if (p / "tools" / "verify_living_mesh.py").is_file(): return p return Path.cwd() def invoke(tool_name: str, argv: list[str] | None = None) -> int: stack = stack_root() tool = stack / "tools" / tool_name if not tool.is_file(): print( f'{{"verdict":"ERROR","reason":"missing_tool","tool":"{tool_name}","stack":"{stack}"}}', file=sys.stderr, ) return 2 return subprocess.call( [sys.executable, str(tool), *(argv if argv is not None else sys.argv[1:])], cwd=str(stack), ) ``` The public entry-point wrappers invoke fixed external filenames. For example, `scripts/join.py`, lines 1–6: ```python #!/usr/bin/env python3 import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) from _stack_invoke import invoke raise SystemExit(invoke("agent_lattice_join.py")) ``` ### Technical Analysis The packaged Skill does not contain the implementations responsible for identity generation, joining, announcement, gossip, directory management, sentinel processing, hub operation, or verification. Instead, each entry point selects a separate stack directory and executes a Python file from its `tools` subdirectory. The stack location can come from the mutable `LYGO_STACK_ROOT` environment variable, a detected ancestor directory, or the current working directory. Before execution, the launcher only verifies that the selected path is a file. It does not verify: - A cryptographic digest or signature - A p ...[truncated 2008 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Bundle the reviewed implementations with the Skill so the audited package contains the code it executes. 2. If external stack tools must remain separate, pin an exact trusted release and verify every executable file against an embedded cryptographic digest or a trusted digital signature before invocation. 3. Require `LYGO_STACK_ROOT` to resolve beneath an explicitly approved canonical directory; fail closed instead of falling back to the current working directory. 4. Resolve the final tool path and verify that it remains inside the approved `tools` directory. 5. Reject symbolic links and require safe ownership and permissions for both the stack root and delegated files. 6. Replace the generic tool-name interface with an immutable allowlist mapping each supported operation to one exact filename. 7. Verify the external stack’s version and compatibility metadata before execution. 8. Document the external stack as a security-sensitive runtime dependency rather than implying that all advertised controls are implemented within this package. 9. Add tests proving that modified files, unknown versions, path escapes, symbolic links, and untrusted stack roots are rejected before subprocess creation. ]]>
Vulnerability Patterns
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (3)

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The described purpose is a constrained, security-focused lattice service, but the detected behavior includes generic subprocess execution, dynamic stack-root discovery, and delegation to arbitrary tools in the surrounding stack. That mismatch is dangerous because operators may trust the skill as a narrowly scoped networking component while it effectively inherits the ability to execute broader local code paths and interact with attacker-controlled filesystem or environment state.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises shell and environment-based operation but declares no explicit tool scope or permission boundaries. In an agent ecosystem, this creates an authorization ambiguity where a host may grant broader execution than intended, increasing the chance of command execution, environment-variable exposure, or unsafe composition with other skills.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
file=sys.stderr,
        )
        return 2
    return subprocess.call(
        [sys.executable, str(tool), *(argv if argv is not None else sys.argv[1:])],
        cwd=str(stack),
    )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.