registry  /  @goplausible/ac2-plugin-claude  /  0.2.11

@goplausible/ac2-plugin-claude@0.2.11

AC2 channel plugin for Claude Code — connects Claude Code to AC2 wallet peers (e.g. Regent) over Liquid Auth (FIDO2) + WebRTC DataChannels.

AI Security Review

scanned 2h ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. No confirmed malicious attack surface, but the package is a Claude Code channel/plugin that can alter agent configuration when the user runs setup and can relay local hook events to its runtime. Wallet signing/payment capability is exposed as explicit MCP tools and requires a paired wallet/user approval.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
User installs/enables the Claude plugin, optionally runs /ac2:setup, starts the MCP/channel server, pairs a wallet, and invokes signing/payment tools.
Impact
Agent extension lifecycle and wallet-payment capability risk if the user grants/uses the plugin; no evidence of unconsented install-time hijack or credential exfiltration.
Mechanism
First-party Claude channel extension with local hook relay, WebRTC wallet pairing, signing, and x402 payment tooling.
Rationale
Source inspection supports a warning-level agent extension lifecycle risk, not malware: the risky Claude settings changes are explicit user-command setup and there is no install-time mutation or concrete exfiltration. The wallet/payment primitives match the package purpose and require a paired wallet plus approval.
Evidence
package.jsondist/server.jscommands/setup.mdhooks/hooks.jsonskills/ac2/SKILL.mdREADME.md.mcp.json.claude-plugin/plugin.json~/.claude/settings.json~/.claude/channels/ac2/hook.port~/.claude/channels/ac2/agent-key.json~/.claude/channels/ac2/paired-peer record
Network endpoints6
liquidauth.goplausible.xyzfacilitator.goplausible.xyzmainnet-api.4160.nodely.devtestnet-api.4160.nodely.devlocalhost:4001127.0.0.1:$P/hook

Decision evidence

public snapshot
AI called this Suspicious at 84.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • commands/setup.md instructs user-invoked writes to ~/.claude/settings.json permissions.allow, channelsEnabled, and allowedChannelPlugins.
  • hooks/hooks.json defines Claude hooks that POST prompt/tool events to local http://127.0.0.1:$P/hook.
  • dist/server.js writes/uses ~/.claude/channels/ac2 state including hook.port, agent DID, pairing records.
  • dist/server.js exposes wallet signing and x402 payment tools that can request transaction signatures.
  • dist/server.js reads Claude config/plugin skill paths and recent transcript tail for status/context helpers.
Evidence against
  • package.json has no preinstall/install/postinstall; only prepublishOnly build lifecycle.
  • Setup mutation is explicit slash-command documentation, not automatic install-time modification.
  • skills/ac2/SKILL.md and dist/server.js state wallet signs after user approval; private keys are not held by the agent.
  • x402 payments enforce wallet account selection and maxAmountPerRequest checks before signing.
  • Network endpoints are package-aligned: Liquid Auth/WebRTC relay, Bazaar/facilitator, Algorand nodes, and user-supplied x402 URLs.
  • No child_process execution in dist/server.js; hook shell commands are static localhost curl relays.
Behavioral surface
Source
ChildProcessCryptoEnvironmentVarsEvalFilesystemNativeBindingsNetwork
Supply chain
HighEntropyStringsMinifiedObfuscatedProtestwareTelemetryUrlStrings
ManifestNo manifest risk signals triggered.
scanned 1 file(s), 1.92 MB of source, external domains: 127.0.0.1, api.devnet.solana.com, api.mainnet-beta.solana.com, api.testnet.solana.com, developer.mozilla.org, example.x402.goplausible.xyz, facilitator.goplausible.xyz, github.com, json-schema.org, mainnet-api.4160.nodely.dev, raw.githubusercontent.com, sola.na, testnet-api.4160.nodely.dev, viem.sh, www.w3.org

Source & flagged code

4 flagged · loading source
dist/server.jsView file
6const __filename = __ac2FileURLToPath(import.meta.url); L7: const __dirname = __ac2Dirname(__filename); L8: var V1e=Object.create;var _3=Object.defineProperty;var j1e=Object.getOwnPropertyDescriptor;var q1e=Object.getOwnPropertyNames;var H1e=Object.getPrototypeOf,Z1e=Object.prototype.has... L9: `:""},this._extScope=e,this._scope=new Ec.Scope({parent:e}),this._nodes=[new wR]}toString(){return this._root.render(this.opts)}name(e){return this._scope.name(e)}scopeName(e){retu... L10: || (${a} == "string" && ${i} && ${i} == +${i})`).assign(s,(0,$r._)`+${i}`);return;case"integer":n.elseIf((0,$r._)`${a} === "boolean" || ${i} === null L11: || (${a} === "string" && ${i} && ${i} == +${i} && !(${i} % 1))`).assign(s,(0,$r._)`+${i}`);return;case"boolean":n.elseIf((0,$r._)`${i} === "false" || ${i} === 0 || ${i} === null`).... L12: || ${a} === "boolean" || ${i} === null`).assign(s,(0,$r._)`[${i}]`)}}}function N4e({gen:t,parentData:e,parentDataProperty:r},n){t.if((0,$r._)`${e} !== undefined`,()=>t.assign((0,$r... L13: missingProperty: ${n}, ... L18: ${new this._window.XMLSerializer().serializeToString(h)}`;return typeof Blob>"u"||this._options.jsdom?Buffer.from(b):new Blob([b],{type:w})}return
Critical
Wallet Drain

Source uses private key material to transfer cryptocurrency funds.

dist/server.jsView on unpkg · L6
6Trigger-reachable chain: manifest.bin -> dist/server.js L6: const __filename = __ac2FileURLToPath(import.meta.url); L7: const __dirname = __ac2Dirname(__filename); L8: var V1e=Object.create;var _3=Object.defineProperty;var j1e=Object.getOwnPropertyDescriptor;var q1e=Object.getOwnPropertyNames;var H1e=Object.getPrototypeOf,Z1e=Object.prototype.has... L9: `:""},this._extScope=e,this._scope=new Ec.Scope({parent:e}),this._nodes=[new wR]}toString(){return this._root.render(this.opts)}name(e){return this._scope.name(e)}scopeName(e){retu... L10: || (${a} == "string" && ${i} && ${i} == +${i})`).assign(s,(0,$r._)`+${i}`);return;case"integer":n.elseIf((0,$r._)`${a} === "boolean" || ${i} === null L11: || (${a} === "string" && ${i} && ${i} == +${i} && !(${i} % 1))`).assign(s,(0,$r._)`+${i}`);return;case"boolean":n.elseIf((0,$r._)`${i} === "false" || ${i} === 0 || ${i} === null`).... L12: || ${a} === "boolean" || ${i} === null`).assign(s,(0,$r._)`[${i}]`)}}}function N4e({gen:t,parentData:e,parentDataProperty:r},n){t.if((0,$r._)`${e} !== undefined`,()=>t.assign((0,$r... L13: missingProperty: ${n}, ... L18: ${new this._window.XMLSerializer().serializeToString(h)}`;return typeof Blob>"u"||this._o…
Critical
Trigger Reachable Dangerous Capability

A package entrypoint or install-time lifecycle script reaches a source file with blocking dangerous behavior.

dist/server.jsView on unpkg · L6
11|| (${a} === "string" && ${i} && ${i} == +${i} && !(${i} % 1))`).assign(s,(0,$r._)`+${i}`);return;case"boolean":n.elseIf((0,$r._)`${i} === "false" || ${i} === 0 || ${i} === null`).... L12: || ${a} === "boolean" || ${i} === null`).assign(s,(0,$r._)`[${i}]`)}}}function N4e({gen:t,parentData:e,parentDataProperty:r},n){t.if((0,$r._)`${e} !== undefined`,()=>t.assign((0,$r... L13: missingProperty: ${n},
Low
Eval

Package source references a known benign dynamic code generation pattern.

dist/server.jsView on unpkg · L11
6const __filename = __ac2FileURLToPath(import.meta.url); L7: const __dirname = __ac2Dirname(__filename); L8: var V1e=Object.create;var _3=Object.defineProperty;var j1e=Object.getOwnPropertyDescriptor;var q1e=Object.getOwnPropertyNames;var H1e=Object.getPrototypeOf,Z1e=Object.prototype.has... L9: `:""},this._extScope=e,this._scope=new Ec.Scope({parent:e}),this._nodes=[new wR]}toString(){return this._root.render(this.opts)}name(e){return this._scope.name(e)}scopeName(e){retu... L10: || (${a} == "string" && ${i} && ${i} == +${i})`).assign(s,(0,$r._)`+${i}`);return;case"integer":n.elseIf((0,$r._)`${a} === "boolean" || ${i} === null L11: || (${a} === "string" && ${i} && ${i} == +${i} && !(${i} % 1))`).assign(s,(0,$r._)`+${i}`);return;case"boolean":n.elseIf((0,$r._)`${i} === "false" || ${i} === 0 || ${i} === null`).... L12: || ${a} === "boolean" || ${i} === null`).assign(s,(0,$r._)`[${i}]`)}}}function N4e({gen:t,parentData:e,parentDataProperty:r},n){t.if((0,$r._)`${e} !== undefined`,()=>t.assign((0,$r... L13: missingProperty: ${n}, ... L18: ${new this._window.XMLSerializer().serializeToString(h)}`;return typeof Blob>"u"||this._options.jsdom?Buffer.from(b):new Blob([b],{type:w})}return
Low
Weak Crypto

Package source references weak cryptographic algorithms.

dist/server.jsView on unpkg · L6

Findings

2 Critical1 High4 Medium8 Low
CriticalWallet Draindist/server.js
CriticalTrigger Reachable Dangerous Capabilitydist/server.js
HighObfuscated
MediumNetwork
MediumEnvironment Vars
MediumProtestware
MediumStructural Risk Force Deep Review
LowNon Install Lifecycle Scripts
LowScripts Present
LowEvaldist/server.js
LowWeak Cryptodist/server.js
LowFilesystem
LowHigh Entropy Strings
LowTelemetry
LowUrl Strings