Back to skill

Security audit

polymarket-exits

Security checks for vulnerabilities and agentic risk

Overview

This is a disclosed Polymarket stop-loss sidecar, but it needs Review because it can run long-lived automated trading code with a sell-authorizing private key through an external package and broad launch paths.

Install only if you intentionally want automated Polymarket exit management. Keep dry-run on until you have reviewed the exact @hypelens/hypelens-agent-guard version, use a dedicated least-privilege exit key, avoid exposing private keys through shell history or Docker environment inspection, and run the watcher in an isolated account or container with clear stop and rollback procedures.

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)

T08 · Insecure Dependencies

Error
Location
scripts/package.json:6
Finding
External Dependency Executes with Wallet and Trading Authority Without Locally Auditable Source<![CDATA[ ## Vulnerability Details **File Location**: `scripts/package.json:6-8`; `scripts/setup.mjs:10-23`; `scripts/start-watcher.mjs:9-14`; `scripts/start-mcp.mjs:9-16` **Vulnerability Type**: Supply-chain trust boundary violation **Risk Level**: High ### Vulnerable Code `scripts/package.json:6-8`: ```json "dependencies": { "@hypelens/hypelens-agent-guard": "0.1.17" } ``` `scripts/setup.mjs:10-23`: ```js let entry; try { const pkgJson = require.resolve('@hypelens/hypelens-agent-guard/package.json'); entry = join(dirname(pkgJson), 'bin', 'agent-guard.js'); } catch { entry = join(scriptsDir, '..', '..', 'bin', 'agent-guard.js'); } if (!existsSync(entry)) { console.error('Missing @hypelens/hypelens-agent-guard. Run: npm install'); process.exit(1); } process.argv = [process.argv[0], entry, 'setup', '--scripts-dir', scriptsDir, ...process.argv.slice(2)]; await import(pathToFileURL(entry).href); ``` `scripts/start-watcher.mjs:9-14`: ```js try { const pkgJson = require.resolve('@hypelens/hypelens-agent-guard/package.json'); const pkg = require(pkgJson); const binRel = (pkg.bin && pkg.bin['agent-guard-watcher']) || 'bin/agent-guard-watcher.js'; const entry = join(dirname(pkgJson), binRel); await import(pathToFileURL(entry).href); ``` `scripts/start-mcp.mjs:9-16`: ```js try { const pkgJson = require.resolve('@hypelens/hypelens-agent-guard/package.json'); const pkg = require(pkgJson); const binRel = (pkg.bin && (pkg.bin['agent-guard-mcp'] || pkg.bin['agent-guard'])) || 'bin/agent-guard-mcp.js'; const entry = join(dirname(pkgJson), binRel); await import(pathToFileURL(entry).href); ``` ### Technical Analysis The project’s local scripts do not implement the substantive setup, watcher, MCP, or trading logic. Instead, they dynamically resolve and import executable modules from `@hypelens/hypelens-agent-guard`. The source of those executable modules is not present in the audited project, preventing this audit from verifying ...[truncated 2230 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Vendor the exact executable dependency source into the reviewed release or include it as an auditable workspace package. 2. Perform a separate source audit of `@hypelens/hypelens-agent-guard@0.1.17`, particularly its signer, networking, MCP, configuration, and order-placement paths. 3. Continue pinning an exact version and lockfile integrity value, and use `npm ci` rather than `npm install` in deployment. 4. Consider `npm ci --ignore-scripts` unless dependency lifecycle scripts have been explicitly reviewed and are required. 5. Verify the expected package archive or critical executable files against independently maintained cryptographic hashes before importing them. 6. Run the watcher in a restricted container or operating-system account with: - A read-only root filesystem where practical. - Minimal writable state directories. - An outbound network allowlist. - No access to unrelated user files or credentials. 7. Use a dedicated signer with narrowly scoped authority, strict position and order limits, and no authority over unrelated funds. 8. Add runtime safeguards such as maximum order size, maximum cumulative daily exit amount, destination and market allowlists, and explicit operator confirmation for exceptional orders. ]]>

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/setup.mjs:14
Finding
Launchers Fall Back to Executing Unverified Modules Outside the Skill Directory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.mjs:14-17`; `scripts/start-watcher.mjs:15-23`; `scripts/start-mcp.mjs:17-25` **Vulnerability Type**: Local module hijacking through an untrusted fallback path **Risk Level**: High ### Vulnerable Code `scripts/setup.mjs:10-23`: ```js let entry; try { const pkgJson = require.resolve('@hypelens/hypelens-agent-guard/package.json'); entry = join(dirname(pkgJson), 'bin', 'agent-guard.js'); } catch { entry = join(scriptsDir, '..', '..', 'bin', 'agent-guard.js'); } if (!existsSync(entry)) { console.error('Missing @hypelens/hypelens-agent-guard. Run: npm install'); process.exit(1); } process.argv = [process.argv[0], entry, 'setup', '--scripts-dir', scriptsDir, ...process.argv.slice(2)]; await import(pathToFileURL(entry).href); ``` `scripts/start-watcher.mjs:15-23`: ```js } catch (e) { try { const localEntry = join( dirname(fileURLToPath(import.meta.url)), '..', '..', 'bin', 'agent-guard-watcher.js', ); await import(pathToFileURL(localEntry).href); ``` `scripts/start-mcp.mjs:17-25`: ```js } catch (e) { try { const localEntry = join( dirname(fileURLToPath(import.meta.url)), '..', '..', 'bin', 'agent-guard-mcp.js', ); await import(pathToFileURL(localEntry).href); ``` ### Technical Analysis When npm package resolution fails, each launcher constructs a path containing `../..` and dynamically imports a module from a parent-level `bin` directory. That directory is outside the audited Skill artifact. The launchers do not validate the resolved canonical path, file owner, permissions, package identity, or cryptographic digest before execution. This creates a local module-hijacking opportunity in installations where another package, process, or user can write to the expected parent-level `bin` directory. The issue is especially significant because dependency resolution failure automatically activates the fal ...[truncated 1937 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove all `../../bin` fallbacks and terminate with an error when the pinned npm dependency cannot be resolved. 2. Resolve executables exclusively from the verified package root returned by `require.resolve`. 3. Canonicalize paths with `realpath` and verify that every selected executable remains under the expected package directory. 4. Do not derive executable paths from writable shared directories. 5. If a development fallback is required: - Require an explicit command-line flag or development-only environment setting. - Use an absolute, administrator-configured path. - Verify an expected cryptographic digest. - Reject symbolic links and files with unsafe ownership or permissions. - Disable the fallback entirely in production builds. 6. Log the canonical executable path and validated package version before import. 7. Add automated tests confirming that missing or malformed dependencies cause a fail-closed exit and never execute parent-directory modules. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
NAUTILUS-SIDECAR.md:6
Finding
Transaction-Authorizing Private Key Is Passed Through Shell and Container Environment Variables<![CDATA[ ## Vulnerability Details **File Location**: `NAUTILUS-SIDECAR.md:6-9`; `NAUTILUS-SIDECAR.md:16-18`; `NAUTILUS-SIDECAR.md:48-56` **Vulnerability Type**: Plaintext sensitive credential exposure **Risk Level**: High ### Vulnerable Code `NAUTILUS-SIDECAR.md:6-9`: ```bash npx @hypelens/hypelens-agent-guard@0.1.17 setup --wallet 0xYourFunder export AGENT_GUARD_EXIT_PK=0xYourExitKey # can SELL funder positions # set exits.dryRun: false in the written policy npx @hypelens/hypelens-agent-guard@0.1.17 watcher ``` `NAUTILUS-SIDECAR.md:16-18`: ```bash npm pack @hypelens/hypelens-agent-guard@0.1.17 && tar -xzf hypelens-hypelens-agent-guard-0.1.15.tgz cp -r package/compose/* . && rm -rf package *.tgz export FUNDER=0xYourFunder EXIT_PK=0xYourExitKey docker compose up -d --build ``` `NAUTILUS-SIDECAR.md:48-56`: ```yaml services: agent-guard-watcher: image: node:22-bookworm-slim working_dir: /app command: bash -lc "npm i @hypelens/hypelens-agent-guard@0.1.17 && npx hypelens-agent-guard setup --wallet $FUNDER && npx hypelens-agent-guard watcher" environment: - AGENT_GUARD_EXIT_PK=${EXIT_PK} volumes: - ./agent-guard-state:/app/state - ./agent-guard-policy:/app/config ``` ### Technical Analysis The documentation instructs users to store a transaction-authorizing private key in shell variables and inject it into a container as a normal environment variable. Environment variables are plaintext process data rather than a dedicated secret-handling mechanism. Exposure opportunities depend on operating-system and container permissions, but may include: - Shell history if users place the assignment directly into commands or scripts. - Parent processes, debugging tools, crash collection, diagnostics, or application logs. - Container inspection by users with Docker or container-runtime access. - Accidental inclusion in environment dumps, support bundles, CI logs, or deployment manifests. - Any dependency executing in the same pr ...[truncated 1698 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace raw private-key environment variables with a dedicated signer service, hardware wallet, managed key service, or platform-specific secret manager. 2. If containers are required, use runtime secret mounts rather than ordinary Compose `environment` entries. 3. Mount the secret as a read-only file with restrictive permissions, read it only when signing, and avoid copying it into application state or logs. 4. Use a dedicated exit key with the minimum possible authority and strict market, order-size, rate, and cumulative-notional limits. 5. Ensure the key cannot transfer unrelated assets or authorize unrelated account operations. 6. Prevent secret values from appearing in shell history, CI output, debugging traces, crash reports, support bundles, and process diagnostics. 7. Restrict Docker daemon and container inspection privileges; access to the container runtime should be treated as host-equivalent administrative access. 8. Add automatic key rotation and an emergency revocation procedure. 9. Document a secure secret-provisioning workflow rather than demonstrating plaintext `export` commands. 10. Audit the dependency to ensure it never logs, persists, transmits, or returns the key through MCP responses. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (7)

Description-Behavior Mismatch

Medium
Confidence
89% confidence
Finding
The launcher for a skill advertised as `polymarket-exits` actually resolves and executes `@hypelens/hypelens-agent-guard`, which creates a supply-chain/behavior mismatch between the declared skill purpose and the code that runs. In an automated trading/risk-management context, this is dangerous because operators may trust they are launching a dedicated exits sidecar while actually delegating control to a different package whose behavior, permissions, and update cadence may differ.

Intent-Code Divergence

Low
Confidence
83% confidence
Finding
The comment says the script starts a pinned dependency, but the code uses `require.resolve` to load whatever local version of `@hypelens/hypelens-agent-guard` is installed, then falls back to a local bin path. That discrepancy can mislead reviewers and operators into assuming immutability and provenance guarantees that do not exist, increasing the chance of running an unexpected or tampered version in a high-trust trading sidecar.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The skill explicitly instructs users to switch from dry-run to live mode by providing a private key and setting exits.dryRun:false, but it does not present a clear safety warning, confirmation step, or operational safeguards for automated live execution. In a trading sidecar that can autonomously place protective exit orders, this omission raises the risk of unintended real-market actions, credential misuse, or loss from misconfiguration.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation explicitly instructs users how to enable live trading by supplying an exit private key and turning off dry-run mode, but it does not include any warning about real-money execution, irreversible trades, or secret-handling risks. In a trading sidecar context, this omission materially increases the chance of accidental live deployment and exposure of sensitive credentials during setup.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The instructions explicitly configure a live trading sidecar with a private key capable of selling positions and note that providing EXIT_PK auto-disables dry-run. In a trading skill, this can directly trigger real market orders and financial loss if a user follows the copy/paste steps without fully understanding that they are arming live exits; the wording emphasizes convenience and immediacy more than operational risk.

Vague Triggers

Medium
Confidence
95% confidence
Finding
The skill metadata includes a very large set of generic trigger terms such as 'risk', 'heartbeat', 'sidecar', 'docker-compose', and related ecosystem names, which can cause the skill to be selected in contexts beyond intended Polymarket stop-management use. In an autonomous trading environment, unintended invocation can lead to unnecessary installation, execution of setup commands, or operational coupling with wallet-related workflows, increasing the chance of misconfiguration or unsafe trading actions.

Vague Triggers

High
Confidence
98% confidence
Finding
The wildcard recommendation pattern '*place*' is ambiguous and can match many unrelated skills or user requests containing the word 'place', causing this trading sidecar to be auto-suggested or chained in inappropriate contexts. Because the skill includes setup and watcher execution steps tied to funded wallet infrastructure, overly broad matching is more dangerous here than in a low-risk informational skill.

Static analysis

No suspicious patterns detected.