Back to skill

Security audit

LYGO Deception Radar

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but it loads an unverified local detector script and can generate unsafe HTML from sample data, so it needs review before use.

Install only if you trust the adjacent lygo-ops-detector installation and the sample suites you will process. Avoid running it with LYGO_STACK_ROOT pointed at untrusted directories, do not host generated HTML from untrusted suite data, and prefer a version-pinned detector plus proper HTML escaping before public deployment.

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 (2)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/build_radar_feed.py:126
Finding

Stored Cross-Site Scripting Through Unescaped Sample IDs

Content
View full analysis
", ">") rows_html.append( f"{r.get('id')}{band}{r.get('ops_score')}{r.get('evasion_index')}{preview}" f"" f"" f"" ) ``` ### Technical Analysis The generated dashboard embeds each sample's `id` directly into an HTML document without HTML escaping. Sample IDs originate in suite JSON loaded by `load_suite()` and can therefore be controlled by anyone able to provide or modify the input suite. Although `text_preview` receives limited angle-bracket replacement, the ID receives no encoding at all. An ID containing HTML markup can terminate the existing `` element and inject executable content. For example: ```json { "id": "", "text": "sample", "label": 0 } ``` The resulting dashboard includes the attacker's `
Remediation
View remediation
{sample_id}" f"{band_text}" f"{escape(str(r.get('ops_score')), quote=True)}" f"{escape(str(r.get('evasion_index')), quote=True)}" f"{preview}" ) ``` 2. Prefer a maintained template engine with automatic HTML escaping rather than constructing the document through formatted strings. 3. Validate sample IDs against a restrictive format, such as `^[A-Za-z0-9_.-]{1,128}$`, when arbitrary characters are unnecessary. 4. Add a restrictive Content Security Policy, preferably disallowing inline scripts: ```html ``` 5. Add regression tests containing IDs and text with tags, quotes, ampersands, event handlers, and script payloads. Verify that they appear only as text in the generated document. ]]>

T08 · Insecure Dependencies

Warning
Location
scripts/build_radar_feed.py:29
Finding

Unverified Dynamic Execution of an External Detector Module

Content
View full analysis
Path | None: candidates = [ SKILL.parent / "lygo-ops-detector" / "scripts" / "lygo_ops_detector.py", Path(r"I:\E Drive\.grok\skills\lygo-ops-detector\scripts\lygo_ops_detector.py"), Path(r"D:\lygo-protocol-stack\clawhub\mirrors\lygo-ops-detector\scripts\lygo_ops_detector.py"), ] env = __import__("os").environ.get("LYGO_STACK_ROOT", "").strip() if env: candidates.append( Path(env) / "clawhub" / "mirrors" / "lygo-ops-detector" / "scripts" / "lygo_ops_detector.py" ) for p in candidates: if p.is_file(): return p return None ``` ```python def build_feed(samples: list[dict], operational: float = 0.65) -> dict[str, Any]: det_path = find_ops_detector() if not det_path: return {"ok": False, "error": "ops_detector_missing", "signature": SIG} sys.path.insert(0, str(det_path.parent)) import lygo_ops_detector as det # noqa: E402 ``` ### Technical Analysis The builder searches several external filesystem locations for `lygo_ops_detector.py`, including a sibling directory, machine-specific absolute paths, and a path derived from `LYGO_STACK_ROOT`. It then prepends the selected directory to `sys.path` and imports the module without validating its cryptographic digest, signature, package identity, or compatible version. Python executes module-level statements during import. Consequently, a substituted `lygo_ops_detector.py` is not merely processed as detector data: it executes with the same operating-system identity and permissions as the user running the builder. The package's own `SIG` constant does not protect this dependency because it is not used to authenticate the selected detector file. ...[truncated 1847 chars]
Remediation
View remediation
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (4)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Dynamic import via __import__()

Medium
Category
Dangerous Code Execution
Confidence
75% confidence
Finding

Dynamic import() can load arbitrary modules at runtime, bypassing static analysis and potentially importing malicious code.

Content

Scanner excerpt · scripts/build_radar_feed.py (reported line 37)May include surrounding context.

python
Path(r"I:\E Drive\.grok\skills\lygo-ops-detector\scripts\lygo_ops_detector.py"),
        Path(r"D:\lygo-protocol-stack\clawhub\mirrors\lygo-ops-detector\scripts\lygo_ops_detector.py"),
    ]
    env = __import__("os").environ.get("LYGO_STACK_ROOT", "").strip()
    if env:
        candidates.append(
            Path(env) / "clawhub" / "mirrors" / "lygo-ops-detector" / "scripts" / "lygo_ops_detector.py"

Context-Inappropriate Capability

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

The script reads LYGO_STACK_ROOT and probes multiple external filesystem locations to locate lygo_ops_detector.py, then later imports and executes code from the resolved path. In a local skill context this broadens the trust boundary beyond bundled/public data and can allow an attacker controlling the environment or filesystem layout to steer the script into loading unintended code.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The generated feed includes detector: str(det_path), which discloses an absolute local path for the detector script. That leaks host filesystem structure into an otherwise public-facing artifact and may expose usernames, drive mappings, repo layout, or installation details useful for reconnaissance.

Content

No source excerpt is available for this finding.