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

@goplausible/ac2-plugin-claude@0.2.10

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 5d ago · by lpm-firewall-ai

No confirmed malicious attack surface was established. The risky primitives are package-aligned: wallet signing/payments, WebRTC relay, local Claude hooks, and optional user-invoked settings changes.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
User installs/loads the Claude plugin, runs its MCP server, pairs a wallet, or invokes setup/sign/x402 tools.
Impact
Can relay messages and permission prompts and request wallet signatures/payments only through the exposed workflow and paired wallet approval.
Mechanism
Claude MCP channel for AC2 wallet pairing, signing, x402 payment, and permission relay.
Rationale
Static inspection found powerful but disclosed, user-invoked AC2 wallet/channel functionality rather than unconsented install-time behavior or concrete theft/exfiltration. Scanner wallet-drain and obfuscation signals appear to come from bundled crypto/payment code and minified esbuild output, with no confirmed malicious flow.
Evidence
package.jsondist/server.js.mcp.json.claude-plugin/plugin.jsonREADME.mdhooks/hooks.jsoncommands/setup.mdcommands/sign.mdskills/ac2/SKILL.md~/.claude/channels/ac2/hook.port~/.claude/channels/ac2/attachments/~/.claude/settings.json
Network endpoints9
liquidauth.goplausible.xyzfacilitator.goplausible.xyzac2.io/v1127.0.0.1api.mainnet-beta.solana.com/api.devnet.solana.comapi.testnet.solana.commainnet-api.4160.nodely.devtestnet-api.4160.nodely.dev

Decision evidence

public snapshot
AI called this Clean at 82.0% confidence as Benign with medium false-positive risk.
Evidence for block
  • dist/server.js is a large bundled runtime with wallet signing, x402 payment, WebRTC/channel, and Claude permission relay capabilities.
  • hooks/hooks.json posts Claude hook events to a localhost listener using a port file under ~/.claude/channels/ac2/.
  • commands/setup.md instructs user-requested edits to ~/.claude/settings.json to allow this plugin's MCP tools and channels.
Evidence against
  • package.json has no install/postinstall/prepare lifecycle; prepublishOnly is publish-time build only.
  • README.md and plugin manifests openly describe wallet pairing, signing, WebRTC, remote permission approval, and state paths.
  • dist/server.js exposes ac2_pair/ac2_sign/x402 tools as MCP/runtime actions requiring paired wallet/user approval, not install-time execution.
  • dist/server.js includes explicit instruction to treat inbound wallet messages as data and not to pair/sign/approve from inbound channel text.
  • No credential harvesting, private key material access, destructive filesystem behavior, or unsolicited exfiltration was confirmed in inspected files.
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