Claudin — Claude Code opened to any LLM (OpenAI, Gemini, DeepSeek, Ollama, and 200+ models)
AI Security Review
scanned 26d ago · by lpm-firewall-ai
Installation automatically executes a launcher-replacement hook. Its runtime updater can install another release of the same lifecycle-enabled package into a local consumer environment.
npm installation, followed by the package update command.
Impact
A later release selected through the updater runs its postinstall hook and mutates the consumer installation.
Mechanism
lifecycle-enabled self-install and launcher replacement
Attack narrative
npm runs install.cjs on installation. That hook resolves an optional platform package and replaces bin/claudin.exe. The bundled updater chooses a local install route; its associated runtime code invokes npm install for @claudiolabs/claudin at stable or latest, allowing a different lifecycle-enabled release to run in the consumer environment. This is a recursive supply-chain path rather than an ordinary fixed dependency.
AI rationale
The automatic postinstall, runtime self-install of a moving release range, binary launcher replacement, and consumer-environment mutation meet the lifecycle self-dependency policy for a malicious install-hook chain.
1import{Kb as p,Lb as HJ}from"./cli-1.1.26-crwbhf2k.mjs";import{Nb as _,Ob as E}from"./cli-1.1.26-14n169e4.mjs";import{FX as o,GX as Q,IX as P}from"./cli-1.1.26-3c44vscp.mjs";import...
L2: if running then
High
Child Process
Package source references child process execution.
1import{Pw as kj,UF as jj,_F as Kj,mB as M,nB as Cj,zw as t}from"./cli-1.1.26-kvt0v6vq.mjs";import"./cli-1.1.26-9x90xrtz.mjs";import"./cli-1.1.26-kb5qx4tp.mjs";import"./cli-1.1.26-h...
L2: `)}function ej(j,q,G){let A=_(G.payload),F=U(A),J={EVENT_NAME:G.eventName,OUTCOME:G.outcome,RULE_ID:q.id,PAYLOAD_JSON:F,ERROR:Y(A,["error","reason"])??"",TASK_SUBJECT:Y(A,["task_su...
L3: `);return{summary:O,body:P}}async function tj(j){let{action:q,rule:G,event:A,runtime:F}=j;if(F.signal?.aborted)return{status:"skipped",reason:"aborted"};if(!F.onSpawnFallbackAgent)...
1import{g3 as qJ,j3 as VJ}from"./cli-1.1.26-g3eqp15d.mjs";import{Fha as q,Iea as $J,Jfa as w,Nha as u,Vea as AJ,fga as m,kca as U,mca as E,rca as ZJ,tca as TJ,vaa as YJ,w$ as W,waa ...
L2: exec "${J}/node_modules/.bin/claudin" "$@"`,493))await BJ(Q,493);return!0}catch(J){return q(J),!1}}async function JQ(J,Q){try{if(!await OJ())return"install_failed";let Z=await W("n...
L3: `)}catch(Q){if(n(Q))return null;throw Q}}async function l(J,Q){let Y=await MJ(J,"w");try{await Y.writeFile(Q.join(`
Medium
Install Persistence
Source writes installer persistence such as shell profile or service configuration.
1import{aua as y,dua as b}from"./cli-1.1.26-zb5hq3ry.mjs";var P0=y(($w)=>{$w.HttpAuthLocation=void 0;(function($){$.HEADER="header",$.QUERY="query"})($w.HttpAuthLocation||($w.HttpAu...
L2: `).slice(0,5).filter((T)=>!T.includes("stackTraceWarning")).join(`
High
Cloud Metadata Access
Source reaches cloud instance metadata or link-local credential endpoints.
•matchType = previous_version_dangerous_delta
matchedPackage = @claudiolabs/claudin@1.1.29
matchedIdentity = npm:QGNsYXVkaW9sYWJzL2NsYXVkaW4:1.1.29
similarity = 0.567
summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta
This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.
dist/chunks/bridgeMain-1.1.26-dnv31x02.mjsView on unpkg
1Cross-file remote execution chain: dist/chunks/bridgeMain-1.1.26-dnv31x02.mjs spawns dist/chunks/cli-1.1.26-0qa3rcd8.mjs; helper contains network access plus dynamic code execution.
L1: import{ea as yJ,fa as xz,ga as rz,ha as cz,ia as iz,ja as kJ}from"./cli-1.1.26-pzpydjmr.mjs";import{la as Tz}from"./cli-1.1.26-xkj6kd3c.mjs";import{va as EJ,wa as TJ,xa as xJ,ya as...
L2: `).filter((K)=>K.length>0)}function VJ(z){let J=z.write??(($)=>process.stdout.write($)),K=z.verbose,Y=0,O="idle",Z="Ready",R="",B="",U="",F="",L="",A=null,_=[],M=!1,y=null,P=0,x=0,...
L3: `)){if(Vz.length===0){w++;continue}let _z=sz(Vz);w+=Math.max(1,Math.ceil(_z/G))}if($.endsWith(`
...
L31: `),$)m(`${V.red($)}
L32: `)},updateSessionStatus($,G,w,Vz){if(w.type==="tool_start")y=w.summary,P=Date.now();p()},clearStatus(){t(),a
High
Cross File Remote Execution Context
Source spawns a local helper that also contains network and dynamic execution context; review data flow before blocking.
1import"./cli-1.1.26-7h1213xq.mjs";import{F as a,H as PG,I as BG,J as IZ,K as BZ}from"./cli-1.1.26-6qzbf8mr.mjs";import"./cli-1.1.26-vpdrb404.mjs";import"./cli-1.1.26-7q7jw0ck.mjs";...
L2: `)),process.exit(1);if(pI()==="windows")process.stderr.write(Q.red(`Error: --tmux is not supported on Windows
...
L26: 1. **Code review** — Invoke the \`${jB}\` tool with \`skill: "code-review"\` and \`args: "medium"\` to get a correctness-bug report on your changes, then fix every reported bug bef...
L27: 2. **Run unit tests** — Run the project's test suite (check for package.json scripts, Makefile targets, or common commands like \`npm test\`, \`bun test\`, \`pytest\`, \`go test\`)...
L28: 3. **Test end-to-end** — Follow the e2e test recipe from the coordinator's prompt (below). If the recipe says t
High
Base64 Obscured Url
Source decodes a Base64-obscured HTTP endpoint at runtime.
Avoid installing @claudiolabs/claudin@1.1.26. Remove it from direct dependencies and check your lockfile for transitive copies.
Choose an independently verified alternative or release. This report does not establish that other versions are safe.
If this version ran, investigate the affected machine and build environment. Rotate credentials it could access and rebuild from a trusted environment.
1import{$i as WZ,Zi as QZ,_i as W0}from"./cli-1.1.26-y82xxzhw.mjs";import{cj as l$,ej as J1}from"./cli-1.1.26-phdsw9kw.mjs";import{Er as D0,Hj as U$,Ij as tZ,Jj as
1import{Pw as kj,UF as jj,_F as Kj,mB as M,nB as Cj,zw as t}from"./cli-1.1.26-kvt0v6vq.mjs";import"./cli-1.1.26-9x90xrtz.mjs";import"./cli-1.1.26-kb5qx4tp.mjs";import"./cli-1.1.26-hc0z3th3.mjs";import
•matchType = previous_version_dangerous_delta
matchedPackage = @claudiolabs/claudin@1.1.29
matchedIdentity = npm:QGNsYXVkaW9sYWJzL2NsYXVkaW4:1.1.29
similarity = 0.567
summary = stored previous version shares package body but lacks this dangerous source file
Critical
Previous Version Dangerous Delta
This package version adds a dangerous source file absent from the previous stored version; route for source-aware review.
dist/chunks/bridgeMain-1.1.26-dnv31x02.mjsView on unpkg
1Cross-file remote execution chain: dist/chunks/bridgeMain-1.1.26-dnv31x02.mjs spawns dist/chunks/cli-1.1.26-0qa3rcd8.mjs; helper contains network access plus dynamic code execution.
L1: import{ea as yJ,fa as xz,ga as rz,ha as cz,ia as iz,ja as kJ}from"./cli-1.1.26-pzpydjmr.mjs";import{la as Tz}from"./cli-1.1.26-xkj6kd3c.mjs";import{va as EJ,wa as TJ,xa as xJ,ya as...
L2: `).filter((K)=>K.length>0)}function VJ(z){let J=z.write??(($)=>process.stdout.write($)),K=z.verbose,Y=0,O="idle",Z="Ready",R="",B="",U="",F="",L="",A=null,_=[],M=!1,y=null,P=0,x=0,...
L3: `)){if(Vz.length===0){w++;continue}let _z=sz(Vz);w+=Math.max(1,Math.ceil(_z/G))}if($.endsWith(`
...
L31: `),$)m(`${V.red($)}
L32: `)},updateSessionStatus($,G,w,Vz){if(w.type==="tool_start")y=w.summary,P=Date.now();p()},clearStatus(){t(),a
High
Cross File Remote Execution Context
Source spawns a local helper that also contains network and dynamic execution context; review data flow before blocking.
1import"./cli-1.1.26-7h1213xq.mjs";import{F as a,H as PG,I as BG,J as IZ,K as BZ}from"./cli-1.1.26-6qzbf8mr.mjs";import"./cli-1.1.26-vpdrb404.mjs";import"./cli-1.1.26-7q7jw0ck.mjs";...
L2: `)),process.exit(1);if(pI()==="windows")process.stderr.write(Q.red(`Error: --tmux is not supported on Windows
...
L26: 1. **Code review** — Invoke the \`${jB}\` tool with \`skill: "code-review"\` and \`args: "medium"\` to get a correctness-bug report on your changes, then fix every reported bug bef...
L27: 2. **Run unit tests** — Run the project's test suite (check for package.json scripts, Makefile targets, or common commands like \`npm test\`, \`bun test\`, \`pytest\`, \`go test\`)...
L28: 3. **Test end-to-end** — Follow the e2e test recipe from the coordinator's prompt (below). If the recipe says t
High
Base64 Obscured Url
Source decodes a Base64-obscured HTTP endpoint at runtime.
7`);return Z}function LZ($,Z,Q){let W=Q?.preserveReasoningContent===!0,J=[],D=new Set,z=new Set;for(let K of $){let F=(K.message??K).content;if(Array.isArray(F)){for(let w of F)if(w.type==="tool_result"&&w.tool_use_id)z.add(w.tool_use_id)}}let X=S$(Z);if(X)J.push({role:"system",content:X});for(let K=0;K<$.length;K++){let V=$[K],F=K===$.length-1,w=V.message??V,M=w.role??V.role,H=w.content;if(M==="user")if(Array.isArray(H)){let L=H.filter((O)=>O.type==="tool_result"),_=H.filter((O)=>O.type!=="tool_result");for(let O of L){let R=O.tool_use_id??"unknown";if(D.has(R))J.push({role:"tool",tool_call_id ...
9`);r=S.pop()??"";for(let A of S){let U=A.trim();if(!U||U==="data: [DONE]")continue;if(!U.startsWith("data: "))continue;let t;try{t=JSON.parse(U.slice(6))}catch{continue}let c=i0(t.usage);for(let u of t.choices??[]){let d=u.delta,G=_Z(d);if(G!=null){if(!K)yield{type:"content_block_start",index:z,content_block:{type:"thinking",thinking:""}},K=!0;yield{type:"content_block_delta",index:z,delta:{type:"thinking_delta",thinking:G}}}if(d.content!=null&&d.content!==""){let j=F.feed(d.content);if(x$(_,d.content),j)if(O)yield*W$(j);else yield*h(j)}if(d.tool_calls){if(P!==null)yield*h(P),P=null;if(f)yield ...
10
11[Content blocked by provider safety filter]`}}}if(w=j,yield{type:"message_delta",delta:{stop_reason:j,stop_sequence:null},...c?{usage:c}:{}},c)M=!0}}if(!M&&c&&(t.choices?.length??0)===0&&w!==null)yield{type:"message_delta",delta:{stop_reason:w,stop_sequence:null},usage:c},M=!0}}}finally{l.releaseLock()}if(!H&&(P!==null||f)){if(K&&!V)yield{type:"content_block_stop",index:z},z++,V=!0;if(yield*G$(),Y)yield*n();w=g??"end_turn",yield{type:"message_delta",delta:{stop_reason:w,stop_sequence:null}}}let s=RZ(_);if(s.totalChunks>0)T(JSON.stringify({type:"stream_stats",model:Z,total_chunks:s.totalChunks, ...
12`);if(V)J.push({type:"text",text:X$(V)})}if(W?.message?.tool_calls)for(let K of W.message.tool_calls){let V=$$(K.function.name,K.function.arguments);J.push({type:"tool_use",id:K.id,name:K.function.name,input:V,...K.extra_content?{extra_content:K.extra_content}:{},...K.extra_content?.google?.thought_signature?{signature:(K.extra_content?.google).thought_signature}:{}})}let Y=D||W?.finish_reason==="tool_calls"?"tool_use":W?.finish_reason==="length"?"max_tokens":"end_turn";if(W?.finish_reason==="content_filter"||W?.finish_reason==="safety")J.push({type:"text",text:`
13
14[Content blocked by provider safety filter]`});return{id:$.id??K$(),type:"message",role:"assistant",content:J,model:$.model??Z,stop_reason:Y,stop_sequence:null,usage:M$($.usage)}}}class F0{messages;reasoningEffort;constructor($,Z){this.messages=new V0($,Z),this.reasoningEffort=Z}}function j1($){JZ(),$0();let Z=new F0({...$.defaultHeaders??{}},$.reasoningEffort);return{beta:Z,messages:Z.messages}}var G0=y(()=>{o0();r0();O$();P$();WZ();DZ();$1();t0();D1();hZ();KZ();e0();gZ();Y1();ZZ();SZ();K1();z1();Q1();s0();Z1();y$();v$();W1();J1();kZ();HZ();q$();MZ();R$();E$();CZ();a0();B$();T$();uZ()});var X ...
15
Long lines were clipped for display.
"./cli-1.1.26-3c44vscp.mjs"
;
import
"./cli-1.1.26-zsf06fnj.mjs"
;
import
{Mfa
as
D,P$
as
z,R$
as
x,Vea
as
s,fga
as
l,v$
as
j,x$
as
I}
from
"./cli-1.1.26-mvjefec1.mjs"
;
import
"./cli-1.1.26-79g0hfrb.mjs"
;
import
"./cli-1.1.26-edg965cj.mjs"
;
import
"./cli-1.1.26-9kzdvxzw.mjs"
;
import
{Xia
as
n}
from
"./cli-1.1.26-chwpygff.mjs"
;
import
"./cli-1.1.26-3gepexgn.mjs"
;
import
"./cli-1.1.26-pf85an2q.mjs"
;
import
"./cli-1.1.26-hk66nk4j.mjs"
;
import
{Lka
as
w}
from
"./cli-1.1.26-n0thzakv ..
.
2if running then
High
Child Process
Package source references child process execution.
2exec "${J}/node_modules/.bin/claudin""$@"`,493))await BJ(Q,493);return!0}catch(J){return q(J),!1}}async function JQ(J,Q){try{if(!await OJ())return"install_failed";let Z=await W("npm",["install",`@claudiolabs/claudin@${Q?Q:J==="stable"?"stable":"latest"}`],{cwd:A(),maxBuffer:1e6});if(Z.code!==0){let $=Error(`Failed to install Claude CLI package: ${Z.stderr}`);return q($),Z.code===190?"in_progress":"install_failed"}return w(($)=>({...$,installMethod:"local"})),"success"}catch(Y){return q(Y),"install_failed"}}async function QQ(){for(let J of p())for(let Q of c(J))try{return await d(Q),!0}catch{} ...
3`)}catch(Q){if(n(Q))return null;throw Q}}async function l(J,Q){let Y=await MJ(J,"w");try{await Y.writeFile(Q.join(`
Medium
Install Persistence
Source writes installer persistence such as shell profile or service configuration.
4`),{encoding:"utf8"}),await Y.datasync()}finally{await Y.close()}}async function wJ(J){let Q=S(J);for(let Y of Object.values(Q)){let Z=await L(Y);if(!Z)continue;for(let $ of Z)if(s.test($)){let X=$.match(/alias\s+claude=["']?([^"'\s]+)/);if(X&&X[1])return X[1]}}return null}async function HQ(J){let Q=await wJ(J);if(!Q)return null;let Y=J?.homedir??t(),Z=Q.startsWith("~")?Q.replace("~",Y):Q;try{let $=await UJ(Z);if($.isFile()||$.isSymbolicLink())return Q}catch{}return null}var s;var o=j(()=>{T();g();s=/^\s*alias\s+claude\s*=/});import{constants as KJ}from"fs";import{access as WJ,readFile as CJ,s ...
5Error: Windows NPM detected in WSL
6
7You're running Claudin in WSL but using the Windows NPM installation from /mnt/c/.
8This configuration is not supported for updates.
9
10To fix this issue:
11 1. Install Node.js within your Linux distribution: e.g. sudo apt install nodejs npm
12 2. Make sure Linux NPM is in your PATH before the Windows version
13 3. Try updating again with 'claudin update'
14`),"install_failed";let{hasPermissions:Z}=await mJ();if(!Z)return"no_permissions";let $=J?`@claudiolabs/claudin@${J}`:"@claudiolabs/claudin",R=await W(Y,Y==="npm"?["install","-g","--force",$]:["install","-g",$],{cwd:z()});if(R.code!==0){let _=new G(`Failed to install new version of claude: ${R.stdout} ${R.stderr}`);return q(_),"install_failed"}return await HJ(),await bJ(Y,$,Q?.onProgress),w((_)=>({..._,installMethod:"global"})),"success"}finally{await fJ()}}async function uJ(){let J=S();for(let[,Q]of Object.entries(J))try{let Y=await L(Q);if(!Y)continue;let{filtered:Z,hadAlias:$}=a(Y);if($)awa ...
15export{rJ as RU,JQ as SU,QQ as TU,YQ as UU,ZQ as VU,g as WU,S as XU,a as YU,L as ZU,l as _U,wJ as $U,HQ as aV,o as bV,zJ as cV,HJ as dV,IQ as eV,kQ as fV,bQ as gV,PQ as hV,vJ as iV,mJ as jV,DQ as kV,fQ as lV,EQ as mV,mQ as nV,uQ as oV,dQ as pV,dJ as qV};
4 Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`}catch(_){if(!P.logger||P.logger?.constructor?.name==="NoOpLogger")console.warn("Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.");else P.logger?.warn?.("Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.")}if(typeof U.$responseBodyText<"u"){if(U.$response)U.$response.body=U.$responseBodyText}try{if(IU.HttpResponse.isInstance(h)){let{headers:_={}}=h,M=Object.entries(_);U.$m ...
14`)}X.push(null)}),X}async function XA($,T){let w=0,P=[],I=$.getReader(),h=!1;while(!h){let{done:_,value:M}=await I.read();if(M)P.push(M),w+=M?.byteLength??0;if(w>=T)break;h=_}I.releaseLock();let U=new Uint8Array(Math.min(T,w)),A=0;for(let _ of P){if(_.byteLength>U.byteLength-A){U.set(_.subarray(0,U.byteLength-A),A);break}else U.set(_,A);A+=_.length}return U}var JA=($,T)=>{if(S($))return XA($,T);return new Promise((w,P)=>{let I=new YA;I.limit=T,$.pipe(I),$.on("error",(h)=>{I.end(),P(h)}),I.on("error",P),I.on("finish",function(){let h=new Uint8Array(Buffer.concat(this.buffers));w(h)})})},YA=clas ...
15If you are using React Native, this API is not yet supported, see: https://react-native.canny.io/feature-requests/p/fetch-streaming-body`);return I.stream()};return Object.assign($,{transformToByteArray:w,transformToString:async(I)=>{let h=awaitw();if(I==="base64")returnG0(h);elseif(I==="hex")returnVT(h);elseif(I===void0||I==="utf8"||I==="utf-8")returng1(h);elseif(typeof TextDecoder==="function")returnnewTextDecoder(I).decode(h);elsethrowError("TextDecoder is not available, please make sure polyfill is provided.")},transformToWebStream:()=>{if(T)throwError(UT);if(T=!0,AT($))return...
16 Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.`}catch(f){if(!w.logger||w.logger?.constructor?.name==="NoOpLogger")console.warn("Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.");else w.logger?.warn?.("Deserialization error: to see the raw response, inspect the hidden field {error}.$response on this object.")}if(typeof X.$responseBodyText<"u"){if(X.$response)X.$response.body=X.$responseBodyText}try{if(B6.HttpResponse.isInstance(I)){let{headers:f={}}=I,G=Object.entries(f);X.$m ...
17export{P0 as Tta,h1 as Uta,D0 as Vta,C$ as Wta,F0 as Xta,ST as Yta,C0 as Zta};
7`)}if((J.file||J.buffer)&&J.content_type){var X=J.filename?J.filename:J.file?X9(J.file):$;if(J.buffer)return H(J.buffer,X,!0);H9(J.file,function(F,M){if(F)return K(F);H(M,X,!0)})}else{if(!J.value)throw Error("value missing for multipart!");if(typeof J.value=="object")return K(Error("Object received for "+$+", expected string."));if(J.content_type)W+=`\r
18`)Y.line++,Y.column=0;elseY.column++;Y.textNode+=Q.substring(k,z-1)}if(G==="<"&&!(Y.sawRoot&&Y.closedRoot&&!Y.strict))Y.state=V.OPEN_WAKA,Y.startTagPosition=Y.position;else{if(!U(G)&&(!Y.sawRoot||Y.closedRoot))B(Y,"Text data outside of root node.");if(G==="&")Y.state=V.TEXT_ENTITY;elseY.textNode+=G}continue;caseV.SCRIPT:if(G==="<")Y.state=V.SCRIPT_ENDING;elseY.script+=G;continue;caseV.SCRIPT_ENDING:if(G==="/")Y.state=V.CLOSE_TAG;elseY.script+="<"+G,Y.state=V.SCRIPT;continue;caseV.OPEN_WAKA:if(G==="!")Y.state=V.SGML_DECL,Y.sgmlDecl="";elseif(U(G));elseif(l(a,G))Y.state=V.OPEN_TAG,Y.tag ...