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

@goplausible/ac2-plugin-codex@0.2.2

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

AI Security Review

scanned 18h ago · by lpm-firewall-ai

Review flagged AI-agent configuration or capability changes. This remains warn-only unless evidence shows foreign-agent hijack through preinstall/install/postinstall, hidden persistence, exfiltration, remote code execution, or other concrete malicious behavior.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
Explicit Codex plugin/MCP use or running dist/server.js
Impact
A paired wallet user can authorize signatures, payments, and Codex approvals through the plugin; misuse depends on user/tool invocation rather than hidden package execution.
Mechanism
User-invoked agent extension with wallet signing/payment and remote approval relay
Policy narrative
When used as a Codex plugin, the package starts an MCP server, can pair with an AC2 wallet over Liquid Auth/WebRTC, spawns a Codex app-server for wallet-originated chat, relays approvals, and can request wallet signatures or x402 payments. These are high-impact agent capabilities, but source inspection shows them as declared plugin behavior requiring explicit use and wallet approval, not hidden install-time malware.
Rationale
The scanner’s wallet-drain and execution labels map to declared wallet-signing/payment and Codex-bridge functionality, with user approval and no private-key collection found. Because the package gives an AI-agent bridge payment/signing and remote approval capabilities, mark suspicious/warn, not malicious/block.
Evidence
package.jsondist/server.js.mcp.json.codex-plugin/plugin.jsonskills/ac2/SKILL.mdREADME.md~/.codex/ac2/tool-proxy.json~/.codex/ac2/codex-thread.json~/.codex/ac2/attachments/AC2_STATE_DIR
Network endpoints8
facilitator.goplausible.xyzmainnet-api.4160.nodely.devtestnet-api.4160.nodely.devlocalhost:4001127.0.0.1liquidauth.goplausible.xyz/download/regent.apklora.algokit.io/testnet/transaction/<TXID>allo.info/tx/<TXID>

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 exposes MCP tools for wallet signing, x402 paid HTTP, and remote Codex approval relay.
  • dist/server.js spawns `codex app-server` and relays command/file approvals to the paired wallet chat.
  • dist/server.js can issue user-supplied HTTP requests and add PAYMENT-SIGNATURE after wallet approval.
  • dist/server.js starts a localhost tool proxy and writes state under AC2_STATE_DIR/default ~/.codex/ac2/.
  • skills/ac2/SKILL.md instructs agents to use ac2_sign and make_http_request_with_x402_ac2 for wallet actions.
Evidence against
  • package.json has no install/postinstall lifecycle hook; prepublishOnly is build-only and not install-time.
  • .codex-plugin/plugin.json declares a Codex plugin manifest and .mcp.json points to this same package via npx.
  • README.md and plugin metadata disclose wallet signing, x402 payments, and remote approvals.
  • Signing/payment flow sends requests to the paired wallet; source says private keys stay in the wallet and user approves/rejects.
  • No evidence of credential harvesting, broad home/project AI-control-surface mutation at install, or unconsented persistence.
Behavioral surface
Source
ChildProcessCryptoEnvironmentVarsEvalFilesystemNativeBindingsNetworkWebSocket
Supply chain
HighEntropyStringsMinifiedObfuscatedProtestwareTelemetryUrlStrings
ManifestNo manifest risk signals triggered.
scanned 1 file(s), 1.87 MB of source, external domains: 127.0.0.1, ac2.io, 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, liquidauth.goplausible.xyz, mainnet-api.4160.nodely.dev, raw.githubusercontent.com, sola.na, testnet-api.4160.nodely.dev, viem.sh, www.w3.org

Source & flagged code

7 flagged · loading source
dist/server.jsView file
6const __filename = __ac2FileURLToPath(import.meta.url); L7: const __dirname = __ac2Dirname(__filename); L8: var $he=Object.create;var v3=Object.defineProperty;var Che=Object.getOwnPropertyDescriptor;var Dhe=Object.getOwnPropertyNames;var Phe=Object.getPrototypeOf,Mhe=Object.prototype.has... L9: `:""},this._extScope=e,this._scope=new cc.Scope({parent:e}),this._nodes=[new dT]}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,Ir._)`+${i}`);return;case"integer":n.elseIf((0,Ir._)`${a} === "boolean" || ${i} === null L11: || (${a} === "string" && ${i} && ${i} == +${i} && !(${i} % 1))`).assign(s,(0,Ir._)`+${i}`);return;case"boolean":n.elseIf((0,Ir._)`${i} === "false" || ${i} === 0 || ${i} === null`).... L12: || ${a} === "boolean" || ${i} === null`).assign(s,(0,Ir._)`[${i}]`)}}}function _6e({gen:t,parentData:e,parentDataProperty:r},n){t.if((0,Ir._)`${e} !== undefined`,()=>t.assign((0,Ir... 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
106Trigger-reachable chain: manifest.bin -> dist/server.js L106: `)} L107: `}function eke(t,e){if(!t.appCallTrace||!t.disassembly)return"";let r=e;return e!==void 0?r=e:r={maxValueWidth:cC,topOfStackFirst:!1},bte(t.appCallTrace,t.disassembly,r)}function t... L108: `);return{content:[yn(a)],details:o}}}}var $Me=Be.Object({refresh:Be.Optional(Be.Boolean({description:"DEPRECATED / no-op (plugin v0.0.84+): every `ac2_capabilities` call now hits ... ... L112: `);return{content:[yn(d)],details:a}}}}var RL=Be.Object({message_base64:Be.String({minLength:1,description:"Base64 of the raw bytes that were signed (same bytes the signer received... L113: ${t.length}`,r=new TextEncoder().encode(e),n=new Uint8Array(r.length+t.length);return n.set(r,0),n.set(t,r.length),Ks(n)}function NL(t,e){let r=e.slice(0,32),n=e.slice(32,64),i=e[6... L114: `)}var g3={type:"object",properties:{},additionalProperties:!1};function Ch(t){return{content:[{type:"text",text:t}]}}async function hhe(t){if(!t)return Ch("No active pairing invit... ... L116: `));if(e.active)return Ch(`Already connected (peer=${e.active.peerDid}). Run ac2_status for details.`);if(e.pendingInvitation&&!mhe(e.pendingInvitation))return hhe(e.pen…
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 · L106
120`)}catch(o){process.stderr.write(`[ac2] could not write tool-proxy endpoint: ${String(o)} L121: `)}}),r}function _he(){let t=vhe();if(!(t&&t.pid!==process.pid))try{yLe(qL())}catch{}}function She(t,e){let r=vhe();if(!r)return Promise.resolve({content:[{type:"text",text:"The AC... L122: `))i.trim()&&process.stderr.write(`[ac2] app-server: ${i}
High
Child Process

Package source references child process execution.

dist/server.jsView on unpkg · L120
112`);return{content:[yn(d)],details:a}}}}var RL=Be.Object({message_base64:Be.String({minLength:1,description:"Base64 of the raw bytes that were signed (same bytes the signer received... L113: ${t.length}`,r=new TextEncoder().encode(e),n=new Uint8Array(r.length+t.length);return n.set(r,0),n.set(t,r.length),Ks(n)}function NL(t,e){let r=e.slice(0,32),n=e.slice(32,64),i=e[6... L114: `)}var g3={type:"object",properties:{},additionalProperties:!1};function Ch(t){return{content:[{type:"text",text:t}]}}async function hhe(t){if(!t)return Ch("No active pairing invit... ... L120: `)}catch(o){process.stderr.write(`[ac2] could not write tool-proxy endpoint: ${String(o)} L121: `)}}),r}function _he(){let t=vhe();if(!(t&&t.pid!==process.pid))try{yLe(qL())}catch{}}function She(t,e){let r=vhe();if(!r)return Promise.resolve({content:[{type:"text",text:"The AC... L122: `))i.trim()&&process.stderr.write(`[ac2] app-server: ${i}
High
Same File Env Network Execution

A single source file combines environment access, network access, and code or shell execution; review context before blocking.

dist/server.jsView on unpkg · L112
106`)} L107: `}function eke(t,e){if(!t.appCallTrace||!t.disassembly)return"";let r=e;return e!==void 0?r=e:r={maxValueWidth:cC,topOfStackFirst:!1},bte(t.appCallTrace,t.disassembly,r)}function t... L108: `);return{content:[yn(a)],details:o}}}}var $Me=Be.Object({refresh:Be.Optional(Be.Boolean({description:"DEPRECATED / no-op (plugin v0.0.84+): every `ac2_capabilities` call now hits ... ... L112: `);return{content:[yn(d)],details:a}}}}var RL=Be.Object({message_base64:Be.String({minLength:1,description:"Base64 of the raw bytes that were signed (same bytes the signer received... L113: ${t.length}`,r=new TextEncoder().encode(e),n=new Uint8Array(r.length+t.length);return n.set(r,0),n.set(t,r.length),Ks(n)}function NL(t,e){let r=e.slice(0,32),n=e.slice(32,64),i=e[6... L114: `)}var g3={type:"object",properties:{},additionalProperties:!1};function Ch(t){return{content:[{type:"text",text:t}]}}async function hhe(t){if(!t)return Ch("No active pairing invit... ... L116: `));if(e.active)return Ch(`Already connected (peer=${e.active.peerDid}). Run ac2_status for details.`);if(e.pendingInvitation&&!mhe(e.pendingInvitation))return hhe(e.pendingInvitat... L117: `)}async function mLe(t,e){return e.
High
Command Output Exfiltration

Source combines command execution, command-output handling, and outbound requests; review data flow before blocking.

dist/server.jsView on unpkg · L106
11|| (${a} === "string" && ${i} && ${i} == +${i} && !(${i} % 1))`).assign(s,(0,Ir._)`+${i}`);return;case"boolean":n.elseIf((0,Ir._)`${i} === "false" || ${i} === 0 || ${i} === null`).... L12: || ${a} === "boolean" || ${i} === null`).assign(s,(0,Ir._)`[${i}]`)}}}function _6e({gen:t,parentData:e,parentDataProperty:r},n){t.if((0,Ir._)`${e} !== undefined`,()=>t.assign((0,Ir... 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 $he=Object.create;var v3=Object.defineProperty;var Che=Object.getOwnPropertyDescriptor;var Dhe=Object.getOwnPropertyNames;var Phe=Object.getPrototypeOf,Mhe=Object.prototype.has... L9: `:""},this._extScope=e,this._scope=new cc.Scope({parent:e}),this._nodes=[new dT]}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,Ir._)`+${i}`);return;case"integer":n.elseIf((0,Ir._)`${a} === "boolean" || ${i} === null L11: || (${a} === "string" && ${i} && ${i} == +${i} && !(${i} % 1))`).assign(s,(0,Ir._)`+${i}`);return;case"boolean":n.elseIf((0,Ir._)`${i} === "false" || ${i} === 0 || ${i} === null`).... L12: || ${a} === "boolean" || ${i} === null`).assign(s,(0,Ir._)`[${i}]`)}}}function _6e({gen:t,parentData:e,parentDataProperty:r},n){t.if((0,Ir._)`${e} !== undefined`,()=>t.assign((0,Ir... 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 Critical4 High4 Medium8 Low
CriticalWallet Draindist/server.js
CriticalTrigger Reachable Dangerous Capabilitydist/server.js
HighChild Processdist/server.js
HighSame File Env Network Executiondist/server.js
HighCommand Output Exfiltrationdist/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