T09 · Insecure Skill Coding Practices
- Location
scripts/interactive-diagram-server.mjs:2- Finding
Unauthenticated Loopback API Permits Cross-Origin Diagram State Modification
- Content
View full analysis
Vulnerability Details
File Location:
scripts/interactive-diagram-server.mjs, lines 2–10
Vulnerability Type: Unauthenticated state-changing HTTP API / localhost cross-origin request abuse
Risk Level: MediumVulnerable Code
js const N=G.createServer((t,e)=>{Z(t,e)}); async function Z(t,e){ const o=new URL(t.url??"/",`http://${t.headers.host??"127.0.0.1"}`), r=q(o.searchParams.get("s")??"default"); try{ if(t.method==="GET"&&o.pathname==="/")K(e); else if(t.method==="GET"&&o.pathname==="/events")Q(r,e); else if(t.method==="GET"&&o.pathname==="/state")h(e,200,b(r).commands); else if(t.method==="GET"&&o.pathname==="/status")h(e,200,nt()); else if(t.method==="GET"&&o.pathname==="/sessions")h(e,200,ot()); else if(t.method==="POST"&&o.pathname==="/cmd")await V(t,e,r); else if(t.method==="POST"&&o.pathname==="/clear") et(r),h(e,200,{ok:!0,session:r,commands:0}); else if(t.method==="GET"&&o.pathname==="/export") O(e,r,o.searchParams.get("format")??"json"); else if(t.method==="POST"&&o.pathname==="/export"){ const n=await A(t), s=typeof n.format=="string"?n.format:"json"; O(e,r,s) } else h(e,404,{ok:!1,error:`Unknown route ${t.method??"GET"} ${o.pathname}`}) }catch(n){ h(e,500,{ok:!1,error:n instanceof Error?n.message:String(n)}) } } async function V(t,e,o){ let r; try{r=await A(t)} catch(s){ h(e,400,{ok:!1,error:s instanceof Error?s.message:String(s)}); return } if(!P(r)){ h(e,400,{ok:!1,error:"Body must be a JSON object with a string cmd field"}); return } const n=b(o); r.cmd==="clear"?n.commands=[]: r.cmd==="init"?n.commands=[r]: n.commands.push(r), F(o,n.commands), R(n,r), h(e,200,{ok:!0,session:o,commands:n.commands.length}) } function P(t){ return!!(t&&typeof t=="object"&&typeof t.cmd=="string") }Technical Analysis
The interactive diagram server exposes state-changing endpoints such as `/cm ...[truncated 3072 chars]
- Remediation
View remediation
Remediation Suggestions
- Generate a cryptographically random capability token when the server starts and require it for every API, SSE, state, and export request.
- Generate a separate high-entropy token for each diagram session instead of treating a human-readable session name as authorization.
- Reject requests with missing or unexpected
Originheaders. Allow only the server’s own loopback origin. - Validate the
Hostheader against the actual loopback listener and reject unexpected hostnames. - Require
Content-Type: application/jsonfor command requests and reject other media types. This adds a browser preflight barrier, although it must not replace authentication. - Implement a restrictive CORS policy and do not return permissive cross-origin headers.
- Remove the predictable
defaultsession or map it internally to an unguessable session capability. - Consider disabling automatic adjacent-port fallback. Otherwise, include the capability only in the exact startup URL and ensure it is required on every fallback port.
- Add CSRF-focused regression tests covering cross-origin simple POST requests to
/cmdand/clear. - Optionally bind each server instance to one session and terminate it automatically after inactivity or successful export to reduce the exposure window.
