Back to skill

Security audit

polymarket-stops

Security checks for vulnerabilities and agentic risk

Overview

This skill can run a live Polymarket exit watcher with wallet-selling authority, but its setup does not make the key-handling, live-mode, dependency, and attribution risks clear enough.

Treat this as a high-risk trading sidecar. Before installing, inspect the @hypelens/hypelens-agent-guard package source, keep dry-run enabled until you deliberately switch to live mode, use a dedicated low-value exit signer rather than a main wallet key, avoid putting private keys in shell history or Docker environment where possible, and confirm whether the Zac builderCode attribution and any fee implications are acceptable.

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)

T08 · Insecure Dependencies

Error
Location
scripts/setup.mjs:11
Finding
Security-Critical Wallet and Trading Operations Are Delegated to an Unreviewed Third-Party Package<![CDATA[ ## Vulnerability Details **File Location**: `scripts/setup.mjs:11-22`; related launch paths in `scripts/start-watcher.mjs:9-23`, `scripts/start-mcp.mjs:9-26`, and dependency declaration in `scripts/package-lock.json:701-718` **Vulnerability Type**: Third-party supply-chain trust and dynamic execution **Risk Level**: High ### Vulnerable Code ```javascript 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); ``` The watcher launcher similarly executes an entry point selected from the dependency's package metadata: ```javascript 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); } catch (e) { try { const localEntry = join( dirname(fileURLToPath(import.meta.url)), '..', '..', 'bin', 'agent-guard-watcher.js', ); await import(pathToFileURL(localEntry).href); } catch { console.error('Missing dependency. Run: npm install (in this scripts/ folder)'); console.error(String(e && e.message ? e.message : e)); process.exit(1); } } ``` The dependency is locked as follows: ```json "node_modules/@hypelens/hypelens-agent-guard": { "version": "0.1.17", "resolved": "https://registry.npmjs.org/@hypelens/hypelens-agent-guard/-/hypelens-agent-guard-0.1.17.tgz", "integrity": "sha512-oDPjyJHHatIM69eiGCthlxtkKewFB8J ...[truncated 2854 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Include the security-critical dependency source in the review scope or vendor a reviewed copy of the relevant executable implementation. 2. Publish and verify reproducible build information for the npm artifact. 3. Retain exact dependency versions and integrity hashes, and use `npm ci` rather than an unconstrained installation workflow. 4. Document all network endpoints, files, environment variables, and wallet operations used by the dependency. 5. Run the watcher in a dedicated low-privilege account or container with a read-only filesystem where possible. 6. Restrict outbound network access to explicitly required Polymarket endpoints. 7. Scope the signer to a dedicated wallet with limited funds and permissions. 8. Require explicit operator confirmation before enabling live transaction execution. 9. Validate resolved executable paths against an allowlist instead of trusting mutable `package.json` `bin` metadata at runtime. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
NAUTILUS-SIDECAR.md:6
Finding
Live Wallet Private Key Is Passed Through Shell and Container Environment Variables<![CDATA[ ## Vulnerability Details **File Location**: `NAUTILUS-SIDECAR.md:6-9`, `NAUTILUS-SIDECAR.md:18-19`, `NAUTILUS-SIDECAR.md:25`, and `NAUTILUS-SIDECAR.md:50-56` **Vulnerability Type**: Plaintext sensitive credential exposure and unsafe live-mode activation **Risk Level**: High ### Vulnerable Configuration ```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 ``` The Docker instructions repeat the same pattern: ```bash export FUNDER=0xYourFunder EXIT_PK=0xYourExitKey docker compose up -d --build ``` The provided Compose example injects the key into the container environment: ```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 ``` The documentation also states: ```text EXIT_PK → setup auto-flips exits.dryRun:false ``` ### Technical Analysis The documented setup places a transaction-signing private key in environment variables. Environment variables are plaintext process configuration rather than a dedicated secret-storage mechanism. Depending on the operating environment, they can be exposed through: - Shell history when included directly in commands or scripts. - CI/CD logs and debugging output. - Process inspection by sufficiently privileged local users. - Docker configuration and container inspection interfaces. - Diagnostic bundles, crash reporting, or accidental environment dumps. - Other processes or extensions with access to the container runtime. The key is particularly sensitive because the documentation e ...[truncated 1600 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not pass a wallet private key through ordinary shell or container environment variables. 2. Use a platform secret manager, hardware wallet, isolated signing service, or permission-restricted secret file mounted at runtime. 3. Use a dedicated exit signer with narrowly scoped approvals and limited funds. 4. Prevent the secret from being written to shell history, Compose files, logs, images, or persistent container metadata. 5. Separate credential configuration from live-mode activation. Supplying a key must not automatically disable dry-run mode. 6. Require a distinct, explicit live-mode flag and an interactive confirmation that identifies the wallet, network, assets, and maximum transaction scope. 7. Default to dry-run after every installation, upgrade, configuration change, or policy reset. 8. Rotate any private key that has already been exposed through logs, scripts, environment dumps, or shared container configuration. 9. Document incident-response procedures for revoking approvals and replacing the exit signer. ]]>

other

Warning
Location
NAUTILUS-SIDECAR.md:25
Finding
Protective Trades Include Third-Party Builder Attribution Not Prominently Disclosed in the Primary Setup Flow<![CDATA[ ## Vulnerability Details **File Location**: `NAUTILUS-SIDECAR.md:25-31`; related disclosures in `BOT.md:5-6`, `ELIZA-COMPANION.md:15`, and `NAUTILUS-SIDECAR.md:60-64` **Vulnerability Type**: Third-party transaction attribution and potential fee side effect **Risk Level**: Medium ### Relevant Documentation ```text Same funder wallet as Nautilus. Dry-run arms immediately. EXIT_PK → setup auto-flips exits.dryRun:false (0.1.17+) so protective SELLs stamp Zac builderCode 0x6f751c1d…7329. Proof: AGENT_GUARD_EXIT_ON_BREACH=1 → exit 10 on first dry breach. Never trade 0x9548…. ``` ```text Official Nautilus Polymarket docs: STOP_MARKET / STOP_LIMIT / TRAILING_STOP_MARKET are not supported by Polymarket. The adapter also hard-codes its own builderCode (fee rate 0). Entries stay Nautilus-attributed. This watcher sits beside the live node and places protective SELLs with Zac code → warm attribution now (fee $ after taker/maker rates >0; ~1% taker ~19–20 Sep). ``` The optional entry-routing recommendation states: ```text Route new entries through @hypelens/polymarket-place / clawhub install pm-desk so entries + exits attribute ($10k notional → $100 @ 1%; $50k → $500). Exit-only underperforms for W1–W3. ``` ### Technical Analysis The stated purpose of the Skill is to implement protective stop behavior. The documentation indicates that protective sell orders additionally stamp a fixed builder code associated with “Zac,” creating third-party attribution unrelated to the minimum technical requirements of stop enforcement. The documentation further discusses anticipated fee revenue if fee rates become active. Although this behavior is mentioned in companion documents, it is absent from the primary installation and execution instructions in `SKILL.md`. Users following only the primary setup flow may therefore activate transactions without informed awareness of the attribution or its possible economic consequences. The reviewed artifact does not contain the depen ...[truncated 1145 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove the fixed builder code from protective orders by default. 2. If attribution is retained, make it an explicit opt-in setting rather than mandatory behavior. 3. Disclose the exact builder identity, transaction metadata, current fee rate, and possible future fee impact in `SKILL.md` before installation or live activation. 4. Provide a neutral mode that submits protective trades without third-party attribution. 5. Display the selected builder code and estimated fee impact before live mode is enabled. 6. Require renewed consent if fee rates or attribution economics change. 7. Add tests or transaction previews proving that disabling attribution removes the builder code from signed orders. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (4)

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The TL;DR instructs users to export a private key capable of selling positions and notes that setup can automatically flip `exits.dryRun:false`, but it does not prominently warn that this enables live automated trading from the user's wallet. In a trading sidecar context, this can cause unintended real-money SELL orders, key mishandling, or rapid liquidation if the user copies commands without understanding the consequences.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The compose and one-line install paths encourage fast deployment of a background watcher that can autonomously submit protective SELL orders, yet they do not clearly warn that `docker compose up` or the provided scripts may immediately arm live trading behavior once an exit key is present. Because this skill is explicitly meant to be installed alongside place-only trading agents, the omission is especially dangerous: users are primed to copy/paste operational commands into live environments.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The manifest uses a very large set of broad trigger terms and pairing metadata, which increases the chance the skill is auto-selected or suggested in contexts beyond the operator's actual intent. Because this skill starts a risk-management sidecar tied to a funded wallet and external watcher scripts, unintended invocation could lead to unnecessary installation, wallet binding, or operational changes in a live trading environment.

Vague Triggers

Medium
Confidence
88% confidence
Finding
Labeling the skill as 'REQUIRED after place-only' is an ambiguous and forceful instruction that can pressure an agent or operator into installing it without verifying compatibility, necessity, or safety boundaries. In a trading context, this is more dangerous because it encourages automatic post-trade workflow changes around risk controls, wallet configuration, and persistent background processes.

Static analysis

No suspicious patterns detected.