registry  /  @goplausible/ac2-plugin-codex  /  0.1.0

@goplausible/ac2-plugin-codex@0.1.0

AC2 plugin for Codex — connects Codex to AC2 wallet peers over Liquid Auth (FIDO2) + WebRTC DataChannels.

AI Security Review

scanned 2d ago · by lpm-firewall-ai

LPM treats this as warn-only first-party agent extension lifecycle risk. No confirmed malware or unconsented install-time AI-agent control hijack was established. The package is a Codex/MCP extension with high-risk wallet signing, paid HTTP, local hook bridge, and remote channel features active when the plugin/server is enabled.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
User loads the Codex plugin or runs the bin/MCP server
Impact
Agent-facing financial/signing capabilities and prompt/tool event relay become available, but inspection did not show silent install persistence, credential theft, or private-key exfiltration.
Mechanism
Codex MCP extension exposing wallet signing, x402 payment, WebRTC channel, and localhost hook bridge
Policy narrative
When enabled, the package starts an MCP server that pairs Codex with an AC2 wallet over Liquid Auth/WebRTC, exposes tools to request wallet signatures and x402 payments, and uses Codex hooks to forward prompt/tool events to a local AC2 listener. These are powerful platform-extension capabilities, but the package does not run them at npm install time or silently rewrite foreign agent configuration.
Rationale
Source inspection supports a warn-level first-party agent extension lifecycle risk rather than a publish block: dangerous wallet/payment capabilities are declared and user-invoked, while consumer install-time control-surface mutation or exfiltration was not found. The bundled/obfuscated server raises review risk, but the observed behavior aligns with the package's documented Codex plugin purpose.
Evidence
package.jsondist/server.js.mcp.json.codex-plugin/plugin.jsonhooks/hooks.jsonskills/ac2/SKILL.mdcommands/setup.mdREADME.md~/.codex/ac2/hook.port~/.codex/ac2/attachments
Network endpoints4
github.com/GoPlausible/ac2-sdkgithub.com/GoPlausible/ac2-sdk/tree/main/packages/ac2-plugin-codexliquidauth.goplausible.xyz/download/regent.apk127.0.0.1:$P/hook

Decision evidence

public snapshot
AI called this Suspicious at 86.0% confidence as Dangerous Capability with medium false-positive risk.
Evidence for warning
  • dist/server.js is a bundled MCP/bin entrypoint with wallet signing, WebRTC/Liquid Auth, approval relay, and x402 payment tools
  • skills/ac2/SKILL.md instructs the agent to use ac2_sign and make_http_request_with_x402_ac2 for wallet signing and paid HTTP resources
  • hooks/hooks.json defines Codex hooks that POST prompt/tool events to a localhost AC2 hook listener via $HOME/.codex/ac2/hook.port
  • dist/server.js writes runtime AC2 state under ~/.codex/ac2, including hook.port and attachments
Evidence against
  • package.json has no install/postinstall/prepare consumer lifecycle hook; only prepublishOnly build workflow
  • Static .mcp.json registers npx @goplausible/ac2-plugin-codex@0.1.0 but is a packaged plugin manifest, not install-time mutation
  • commands/setup.md explicitly says not to edit Claude settings files for this plugin
  • Signing/payment flows are documented as user-approved wallet actions; no private-key harvesting found
  • No confirmed credential exfiltration or destructive behavior found by source inspection
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