Back to skill

Security audit

X Layer Execution Guard

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real X Layer trading guard, but it handles wallet execution and credentials in ways users should review carefully before installing.

Install only if you are comfortable granting a skill access to OnchainOS API credentials and a logged-in Agentic Wallet. Use proof or --no-execute mode by default, do not rely on mock execute verdicts for real trades, avoid running it in projects with sensitive .env files, pin dependencies yourself, and only enable agentic-wallet mode after independently confirming the exact token pair, amount, wallet, chain, and slippage.

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

T09 · Insecure Skill Coding Practices

Warning
Location
runtime/route_referee/client.py:16
Finding
Configurable API endpoint can receive OnchainOS authentication credentials<![CDATA[ ## Vulnerability Details **File Location**: `runtime/route_referee/client.py:16, 65-81` **Vulnerability Type**: Authentication credential disclosure through an unvalidated destination override **Risk Level**: Medium ### Vulnerable Code ```python API_BASE_URL = os.getenv("ONCHAINOS_API_BASE", "https://web3.okx.com").rstrip("/") ``` ```python return { "OK-ACCESS-KEY": self.api_key, "OK-ACCESS-SIGN": self._sign(timestamp, method, request_path, body), "OK-ACCESS-TIMESTAMP": timestamp, "OK-ACCESS-PASSPHRASE": self.passphrase, "Content-Type": "application/json", "User-Agent": "xlayer-route-referee/1.0", } ``` ```python response = self.session.request( method=method.upper(), url=f"{self.base_url}{path}", params=params or None, headers=headers, timeout=self.timeout, ) ``` ### Technical Analysis The destination for authenticated API requests is taken directly from the `ONCHAINOS_API_BASE` environment variable. The client does not enforce HTTPS, validate the hostname, or restrict overrides to the documented OKX endpoint. Regardless of the selected destination, the request includes the OnchainOS API key, API passphrase, timestamp, and valid HMAC request signature. Although the signature is generated correctly, sending these headers to an arbitrary endpoint breaks the trust boundary expected for authentication material. The Base64 operation at `runtime/route_referee/client.py:58` is standard encoding of an HMAC-SHA256 digest. It is not, by itself, a covert exfiltration mechanism. The actual exposure arises from attaching authentication headers to an unvalidated, configurable destination. ### Attack Path 1. An attacker or compromised execution environment sets `ONCHAINOS_API_BASE` to an attacker-controlled URL. 2. The user runs any real route check with valid OnchainOS credentials. 3. The client constructs authentication headers for the request. 4. The request is sent to the substituted endpoint. 5. The attacker ...[truncated 718 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Hardcode or allowlist the production endpoint `https://web3.okx.com`. - Enforce HTTPS and reject URLs containing unexpected schemes, hosts, ports, user information, or path prefixes. - Validate the final request hostname immediately before attaching authentication headers. - If custom endpoints are required for development, require an explicit unsafe-development flag and do not use production credentials with them. - Separate request construction from credential attachment so authentication headers are only added after destination validation. - Document and apply least-privilege scopes to all OnchainOS credentials. - Rotate affected credentials if they may have been used while `ONCHAINOS_API_BASE` pointed to an untrusted endpoint. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
runtime/execution_guard/guard.py:89
Finding
Real route-check failures fail open to a mock execute verdict<![CDATA[ ## Vulnerability Details **File Location**: `runtime/execution_guard/guard.py:89-91, 520-543` **Vulnerability Type**: Fail-open security decision and unsafe mock fallback **Risk Level**: Medium ### Vulnerable Code ```python except Exception as e: print(f"Real API error: {e}") return await self._run_mock(intent, response) ``` ```python async def _run_mock(self, intent: GuardIntent, response: GuardResponse) -> GuardResponse: """Fallback to mock implementation if no real API.""" verdict = PreExecutionVerdict() if intent.to_token.upper() == "WBTC": verdict.verdict = "block" verdict.risk_level = "high" verdict.decision = {"action": "block", "reason": "Mock: insufficient liquidity"} else: verdict.verdict = "execute" verdict.risk_level = "low" verdict.recommended_route = RecommendedRoute( dex_name="Mock", dex_id="mock", output_amount="1.0", output_symbol=intent.to_token, price_impact_percent="0", route_concentration_score="0.65", fallback_count=4 ) verdict.decision = {"action": "execute", "rationale": "Mock mode"} response.pre_execution = verdict response.agent_summary = "Mock mode - no API credentials" return response ``` ### Technical Analysis The top-level guard catches every exception raised during the real route-evaluation and execution pipeline and converts it into mock output. For every destination token other than WBTC, the mock path assigns a low-risk `execute` verdict without performing actual liquidity, honeypot, tax, fallback, or price-impact validation. This fallback is not restricted to an explicit testing mode or to missing credentials. Network failures, malformed API responses, parsing errors, endpoint manipulation, and unexpected runtime defects all produce the same mock recommendation. The current invocation returns immediately from the mock path and therefore does not directly execute a wallet trad ...[truncated 1269 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Fail closed when a real API call or parser fails by returning `block` or `retry` with `risk_level="high"`. - Restrict mock behavior to an explicit command-line option such as `--mock`. - Add a machine-readable mode field, such as `evidence_mode="mock"`, and require consumers to reject mock results for authorization. - Never emit `execute` from mock mode; use a non-actionable verdict such as `test_only`. - Catch narrowly scoped exceptions and distinguish network errors, validation failures, API rejection, and programming defects. - Ensure wallet execution and downstream integrations require a successfully completed real assessment rather than relying solely on the textual verdict. - Add tests proving that all API and parsing failures prevent live authorization. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
runtime/execution_guard/guard.py:359
Finding
Unnecessary environment and dotenv secrets are passed to a configurable child executable<![CDATA[ ## Vulnerability Details **File Location**: `runtime/execution_guard/guard.py:359-383` **Vulnerability Type**: Excessive secret exposure to a child process **Risk Level**: Low ### Vulnerable Code ```python def _onchainos_env(self) -> Dict[str, str]: env = os.environ.copy() env.update(self._read_env_file(Path.home() / ".config" / "onchainos.env")) env.update(self._read_env_file(Path.cwd() / ".env")) env.update(self._read_env_file(Path.cwd() / ".env.local")) env["PATH"] = f"{Path.home() / '.local' / 'bin'}:{env.get('PATH', '')}" return env def _onchainos_bin(self) -> str: configured = os.getenv("ONCHAINOS_BIN") if configured: return configured local_bin = Path.home() / ".local" / "bin" / "onchainos" if local_bin.exists(): return str(local_bin) return shutil.which("onchainos") or "onchainos" def _run_onchainos(self, args: List[str], timeout: int) -> Dict[str, Any]: try: completed = subprocess.run( [self._onchainos_bin(), *args], env=self._onchainos_env(), text=True, capture_output=True, timeout=timeout, check=False, ) ``` ### Technical Analysis The Skill copies the complete parent process environment and then merges every key from `.env` and `.env.local` in the current working directory. This combined environment is passed to the `onchainos` child process, even though the child requires only a limited set of wallet and OnchainOS configuration values. The executable can also be selected using `ONCHAINOS_BIN`. There is no validation of its canonical path, ownership, or integrity. No shell is used, so command-line fields do not create direct shell injection; the risk is instead that an incorrect, replaced, or attacker-selected executable receives unrelated secrets from the parent environment and generic project dotenv files. ### Attack Path 1. The host process or current project dotenv files contain ...[truncated 1136 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Build a minimal child-process environment from an explicit allowlist instead of copying `os.environ`. - Load only documented OnchainOS variables from `~/.config/onchainos.env`. - Do not automatically load generic `.env` or `.env.local` files from the current working directory. - Resolve the executable to an absolute path and validate its ownership and permissions before execution. - Remove `ONCHAINOS_BIN` in production, or restrict it to explicitly trusted paths. - Use a sanitized `PATH` that excludes writable or untrusted directories. - Run the wallet CLI in an isolated process context containing no unrelated application credentials. - Preserve the existing argument-array invocation and continue avoiding `shell=True`. ]]>

T08 · Insecure Dependencies

Note
Location
requirements.txt:1
Finding
Unbounded dependency version prevents reproducible installation<![CDATA[ ## Vulnerability Details **File Location**: `requirements.txt:1` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Low ### Vulnerable Code ```text requests>=2.31.0 ``` The documented installation command in `SKILL.md:37-40` is: ```bash python3 -m pip install --user -r "$SKILL_DIR/requirements.txt" ``` ### Technical Analysis The dependency specification accepts any current or future release of `requests` at or above version 2.31.0. No upper bound, lockfile, or package hash is supplied. Consequently, the installed dependency graph can differ from the version reviewed during this audit. This is not evidence that the current `requests` package is malicious. The security issue is the non-reproducible trust decision: a future compromised, incompatible, or unexpectedly changed release remains eligible for automatic installation. ### Attack Path 1. A future dependency release or transitive dependency accepted by the version constraint becomes compromised or behaves incompatibly. 2. A user follows the documented installation command. 3. The package resolver selects that accepted version from the configured package index. 4. Installation or runtime code from the selected package executes with the installing user's privileges. 5. The compromised component can access data and network resources available to that user and process. Successful exploitation depends on compromise of the configured package source or an accepted dependency release; no dependency-confusion package name was identified. ### Impact Assessment A compromised dependency could execute with the privileges of the user installing or running the Skill. This could expose environment credentials, alter user-owned files, or perform network activity. The practical scope is limited by the user's operating-system permissions and the environment in which installation or execution occurs. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin `requests` and all transitive dependencies to reviewed versions. - Generate and commit a lockfile appropriate for the deployment workflow. - Require cryptographic package hashes, for example through a hash-locked requirements file and `pip --require-hashes`. - Review dependency updates before changing pinned versions. - Use a trusted package index and secure repository configuration. - Add automated vulnerability scanning and dependency-update monitoring. - Install dependencies in an isolated virtual environment rather than directly into the user's general package environment. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (16)

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
A second independent mismatch report indicates the skill may only perform local CLI or wallet availability checks while claiming to block, resize, test, or execute swap intents safely. In the context of an execution guard for financial transactions, overstating defensive behavior is especially risky because it can directly influence automated trading or wallet decisions without the promised safeguards.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
A second independent mismatch report indicates the skill may only perform local CLI or wallet availability checks while claiming to block, resize, test, or execute swap intents safely. In the context of an execution guard for financial transactions, overstating defensive behavior is especially risky because it can directly influence automated trading or wallet decisions without the promised safeguards.

Env Variable Harvesting

High
Category
Data Exfiltration
Content
return values

    def _onchainos_env(self) -> Dict[str, str]:
        env = os.environ.copy()
        env.update(self._read_env_file(Path.home() / ".config" / "onchainos.env"))
        env.update(self._read_env_file(Path.cwd() / ".env"))
        env.update(self._read_env_file(Path.cwd() / ".env.local"))
Confidence
98% confidence
Finding
Copying the full process environment into a child execution context is classic environment harvesting behavior because it propagates potentially sensitive secrets unrelated to the task. In this skill, those secrets are then combined with additional local credential files and handed to an external executable, expanding the blast radius if the binary, logs, or downstream tooling are compromised.

Credential Access

High
Category
Privilege Escalation
Content
def _onchainos_env(self) -> Dict[str, str]:
        env = os.environ.copy()
        env.update(self._read_env_file(Path.home() / ".config" / "onchainos.env"))
        env.update(self._read_env_file(Path.cwd() / ".env"))
        env.update(self._read_env_file(Path.cwd() / ".env.local"))
        env["PATH"] = f"{Path.home() / '.local' / 'bin'}:{env.get('PATH', '')}"
        return env
Confidence
97% confidence
Finding
Reading ~/.config/onchainos.env and the current directory's .env files is credential access behavior that can capture wallet and API secrets beyond what a route guard strictly needs. In an agent skill, this is especially risky because untrusted prompts or orchestration may cause the skill to use local secrets to perform high-impact actions.

Credential Access

High
Category
Privilege Escalation
Content
env = os.environ.copy()
        env.update(self._read_env_file(Path.home() / ".config" / "onchainos.env"))
        env.update(self._read_env_file(Path.cwd() / ".env"))
        env.update(self._read_env_file(Path.cwd() / ".env.local"))
        env["PATH"] = f"{Path.home() / '.local' / 'bin'}:{env.get('PATH', '')}"
        return env
Confidence
97% confidence
Finding
Reading .env.local adds another undeclared credential source that may contain sensitive developer or production wallet material. Because the skill can proceed to invoke a fund-moving CLI, this local secret discovery meaningfully increases the chance of unauthorized or surprising use of high-value credentials.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises and instructs use of shell, network, filesystem, and environment-dependent operations but does not declare any tool scope or permission boundaries. In an agent setting, this increases the chance the skill will be run with overly broad ambient privileges, making unintended command execution, credential access, file modification, or network actions more likely.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The skill goes beyond analysis and proof generation by spawning a local wallet CLI and executing a swap. In an agent skill context this is dangerous because a seemingly advisory guard can directly move funds, and the same code path can be triggered from intent data once credentials are present.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
Live trade execution can occur without a user-facing confirmation checkpoint at the moment funds may move. In an autonomous-agent setting, this increases the risk of unintended or manipulated swaps being executed silently once a prior verdict returns 'execute'.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The skill reads process environment and local .env files to assemble credentials for the OnchainOS CLI. This broad credential-loading behavior exceeds simple route judgment and proof generation, and exposes sensitive wallet/API material to any code path that can invoke the subprocess or inspect resulting errors/output.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def _run_onchainos(self, args: List[str], timeout: int) -> Dict[str, Any]:
        try:
            completed = subprocess.run(
                [self._onchainos_bin(), *args],
                env=self._onchainos_env(),
                text=True,
Confidence
95% confidence
Finding
The skill invokes a local executable via subprocess to perform wallet status checks and swap execution. Although arguments are passed as a list rather than through a shell, this still grants the skill host command execution capability and can trigger real on-chain actions using local credentials, making compromise or misuse materially dangerous.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The model sets execute_after_verdict=True by default in GuardIntent, which means a swap may proceed automatically unless callers explicitly disable execution. In a skill designed for autonomous agent trading and wallet execution, unsafe defaults materially increase the chance of unintended or unauthorized on-chain transactions, especially if upstream validation, prompting, or policy checks fail.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run(args: list[str], timeout: int = 10) -> dict:
    try:
        completed = subprocess.run(
            [onchainos_bin(), *args],
            text=True,
            capture_output=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Unpinned Dependencies

Low
Category
Supply Chain
Content
requests>=2.31.0
Confidence
96% confidence
Finding
The dependency is specified as `requests>=2.31.0`, which allows any future release to be installed without review. This weakens build reproducibility and can unintentionally pull in a vulnerable or breaking version of `requests`, which is especially relevant for an agent skill that may make network calls as part of transaction or guard logic.

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
90% confidence
Finding
Because `requests` is not pinned, there is no way to verify from this manifest whether deployment will use a patched or vulnerable release despite known advisories affecting some versions. In a skill described as performing pre-execution checks and optional wallet execution, uncertain dependency state increases supply-chain and network-handling risk, since HTTP client flaws could affect credential handling, TLS behavior, or request security.

Intent-Code Divergence

Low
Confidence
97% confidence
Finding
The inline comment claims a specific safety behavior: "Use higher price impact protection to avoid errors." However, the actual quote call only passes amount, token addresses, and dex_ids, with no visible price-impact or slippage protection argument. This is an active documentation/code contradiction, not merely missing detail.

Missing User Warnings

Low
Confidence
82% confidence
Finding
The client sends network requests to an external API using authentication headers derived from API credentials, but this file contains no confirmation prompt, user-facing log, or warning about transmitting request metadata and token-related parameters off-system. Because network transmission of authenticated data is safety-relevant, some form of disclosure is expected unless documented elsewhere.

Static analysis

No suspicious patterns detected.