T09 · Insecure Skill Coding Practices
- Location
scripts/check-project.mjs:22- Finding
Validator Executes Untrusted Project Files in an Unsafe Node.js VM Context
- Content
View full analysis
- Remediation
View remediation
Security audit
Security checks for vulnerabilities and agentic risk
The skill largely matches an offline wireframe tool, but it has unsafe paths where a project can execute code during validation or load arbitrary screen scripts.
Use this skill only with projects you generated or otherwise trust. Be careful opening or validating wireframe projects from other people until screen.source is restricted to local src/screens files and the checker no longer executes project JavaScript directly. The annotation localStorage and export features are disclosed, but update or avoid the pinned Playwright dev dependency if you install development dependencies.
scripts/check-project.mjs:22Validator Executes Untrusted Project Files in an Unsafe Node.js VM Context
starter/framework/runtime/loader.js:25Unchecked Screen Source Allows Mutable Remote JavaScript Execution
The declared description emphasizes creating or revising offline multi-screen wireframes using Vue 3 Global Build with no build step and direct file opening. While the code does support offline multi-screen prototype viewing and does bridge to Vue screen components, its actual primary behavior is a prebuilt board/runtime implemented in React, not a straightforward Vue-only wireframe implementation. More importantly, it contains substantial undeclared capabilities: AI-oriented review mode that inspects DOM nodes and generates modification prompts, persistent annotations with local draft storage and synchronization prompts, JSON import/export for annotations, and PNG/ZIP export of screens using extra vendor libraries. These are material capabilities not represented in the description, so the description does not accurately capture what this code chunk actually does.
The declared description focuses on creating and revising offline multi-screen wireframes and page-flow prototypes in Vue 3 with no build step. The actual code does not implement wireframe creation, screen flows, Vue-based UI behavior, or prototype editing. Instead, it is a generic file export/download utility (FileSaver) used to save blobs or download remote/local resources, including making GET and HEAD requests to URLs. While such a library could be a supporting dependency in a larger prototyping tool, this code chunk by itself performs a materially different function than the declared primary purpose, so this chunk is a mismatch.
The declared description focuses on creating editable offline multi-screen wireframes and prototypes in Vue 3 without a build step. The actual code shown is html2canvas 1.4.1, a library used to capture/render HTML DOM into a canvas. That behavior is materially different from the stated primary purpose and introduces an undeclared screenshot/rendering capability. While such a library could be used as a supporting detail in a prototyping tool, the provided chunk itself does not implement wireframe creation logic and instead reflects a separate capture utility, so this code chunk does not accurately match the declared description.
This code chunk does not implement wireframe creation, Vue-based screen prototyping, multi-screen UI flow logic, or file:// offline page authoring behavior. Instead, it is a general-purpose third-party archive library (JSZip). While such a library could be a supporting dependency in a larger prototyping tool, this chunk by itself performs unrelated archive manipulation capabilities that are not reflected in the declared description. Therefore, the supplied code chunk's actual behavior does not accurately match the declared purpose.
This code chunk is not an app-specific wireframing or page-flow prototype generator. It is a third-party vendor runtime: react-dom.production.min.js. Its primary behavior is to support React component rendering and DOM event management, not to create or revise offline multi-screen wireframes. The declared description specifically emphasizes Vue 3 Global Build and a no-build-step Vue-based deliverable, while the actual code is ReactDOM infrastructure. That is a material framework and purpose mismatch, not merely an implementation detail.
This code chunk is clearly a bundled vendor dependency: react-dom.production.min.js. Its primary purpose is to provide the React DOM renderer/runtime, including root creation, hydration, unmounting, portal creation, scheduling, and internal reconciliation support. That materially differs from the declared skill purpose of producing offline multi-screen wireframes and page-flow prototypes specifically with Vue 3 global build and plain JS files. While a prototyping tool could include framework libraries as implementation details, this file directly contradicts the declared framework choice (Vue 3) by shipping React DOM instead. That is a meaningful description-to-behavior mismatch.
The description emphasizes a Vue 3-based offline wireframing/prototyping solution. The actual code is a stock React production build, which is a materially different framework and does not itself implement the declared wireframe/prototype functionality. While including a frontend library could be a supporting detail, using React directly contradicts the explicit claim that the skill uses Vue 3 Global Build. Therefore this is a clear description-behavior mismatch.
The declared description presents a skill whose purpose is to produce offline, AI-editable wireframes and page-flow prototypes. The supplied code is instead a vendor framework file (vue.global.js) from Vue 3. It contains low-level runtime and compiler behavior such as patchProp, event handling, custom element support, transitions, v-model directives, rendering/app mounting, tokenizer/parser, and transform/codegen utilities. While Vue could be used as a supporting dependency in such a skill, this chunk itself does not implement the claimed wireframe/prototype creation behavior. Therefore the description does not accurately represent what this specific code chunk actually does.
The declared description emphasizes creating or revising offline wireframes/prototypes with Vue 3 global build and no build step. The supplied code does support offline prototype viewing/editing and mounts Vue screens, so it is related. However, the actual code chunk is materially broader and partly different in architecture: it is a substantial React-based board/runtime wrapper around Vue screens, not simply a Vue-global-only multi-screen prototype scaffold. More importantly, it includes significant undeclared capabilities beyond wireframe rendering/page flow: export to PNG/ZIP using extra libraries, DOM-based review tooling that builds AI modification prompts, annotation persistence and synchronization workflows using localStorage and JSON import/export, clipboard copying, and fullscreen/settings utilities. These are substantive capabilities and resource uses absent from the declared purpose, so this should be flagged as a description-behavior mismatch.
The declared purpose is about generating/editing offline Vue-based wireframes and interactive prototypes. The actual code does not create screens, page flows, or Vue UI logic; it is a generic file-saving utility. It adds download/save capabilities, including fetching URLs and saving blobs, which are not mentioned in the description and represent a materially different primary purpose for this code chunk. While such a library could support exporting prototype files, this specific chunk is not itself implementing wireframe creation behavior, so the description does not accurately represent what the code actually does.
The declared description focuses on creating or revising offline multi-screen wireframes and page-flow prototypes using Vue 3 without a build step. The provided code is instead a vendored minified copy of html2canvas, a browser library for screenshotting/rendering HTML into canvas. That is a different concrete capability and is not disclosed in the description. While such a library could be used as a supporting implementation detail inside a prototyping tool, this specific chunk by itself does not implement the declared wireframing/prototyping behavior and instead provides an additional capture/export-related function. Therefore this code chunk does not accurately match the declared purpose.
The declared purpose is a wireframing/prototyping tool for offline Vue-based multi-screen UI flows. The actual code chunk is a third-party archive-processing library (JSZip) unrelated to generating or revising wireframes, page flows, or Vue screens. While such a library could be a supporting dependency in some larger project, this code chunk itself implements ZIP file manipulation capabilities that are not reflected in the description. Therefore the code's actual behavior does not accurately represent the declared purpose.
This is a strong description-behavior mismatch. The declaration describes a skill for producing offline, AI-editable wireframes/prototypes specifically with Vue 3 global build and no build step. The actual code chunk is an unrelated third-party minified ReactDOM runtime vendor file. It does not implement wireframe creation behavior itself; instead it supports rendering React components, synthetic events, reconciliation, hydration, and scheduling. The primary purpose, framework choice, and deliverable architecture all differ materially from the declared description.
The description promises a skill centered on creating or revising offline wireframes/prototypes specifically with Vue 3 Global Build and multi-file JavaScript screens. The actual code is not application logic for wireframes or page flows; it is a bundled minified React DOM runtime. Its primary purpose is rendering and hydrating React component trees in the DOM, including APIs like createRoot, hydrateRoot, render, createPortal, and unmounting. That is materially different from the declared purpose and explicitly inconsistent with the stated Vue 3-based implementation approach. This is not merely a supporting detail because the framework/runtime choice is central to the declared architecture.
The description says the skill is for generating offline wireframes/prototypes specifically with Vue 3 Global Build and plain JavaScript files. The actual code is a bundled third-party React production runtime, not Vue, and it does not itself implement wireframe generation, page-flow editing, or prototype screens. While including a framework library can be a supporting implementation detail, here the framework is materially inconsistent with the declared technology choice and primary purpose. Therefore the code chunk does not accurately represent the declared description.
The description claims a skill whose purpose is to create or revise offline multi-screen wireframes/prototypes. The provided code does not implement that behavior; it is a third-party vendor copy of the Vue global build. While Vue could be a supporting dependency for such a skill, this chunk itself only supplies general reactive state management and UI runtime machinery. There is no evidence here of generating screens, flows, editable mockups, file:// packaging logic, or other prototype-specific behavior. Therefore the supplied code chunk does not accurately represent the declared skill purpose.
The description claims the skill creates or revises offline multi-screen wireframes and page-flow prototypes. However, the provided code is a vendor framework file from Vue's global build, not application logic for producing wireframes. While bundling Vue could support such a tool, this chunk's actual behavior is generic framework/runtime/compiler functionality unrelated to the declared end-user capability. This is a material purpose mismatch for the supplied code chunk.
Referenced artifact was not completely inspected
- 有可用 Node.js / `.mjs` 运行环境时,`check-project.mjs` 通过,无缺屏、孤儿 screen、断链、重复 id 或不合规依赖;环境不能运行时可跳过脚本校验,不将 Node.js 作为交付或使用前提。
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
1. Enable multi-select and click the two elements to swap (use the breadcrumb to reach the right level—e.g. two list-item roots, not the text inside).
2. Set type to **Reorder**.
3. State the goal clearly, e.g. “Swap these two nodes” or “Move A after B”.
4. Add to the list → copy the Prompt to AI.
Multi-select also works for “one note, several places”: select the same kind of copy in header and footer and write one shared requirement.
The package pins Playwright 1.52.0, which is reported as affected by CVE-2025-59288 involving browser downloads/installations without authenticity verification. In a development workflow, this can expose the environment to tampered browser binaries or a supply-chain compromise during Playwright setup, potentially leading to code execution or a compromised test environment. The skill context increases concern because this package is intended for local/offline deliverables and developer tooling, where Playwright is likely used during generation or testing on the analyst's machine.
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
/* PREBUILT VUE GLOBAL POC BOARD BRIDGE. BUSINESS SCREENS REQUIRE NO BUILD. */
(()=>{var on=React.createContext(null);function Io(e){return e.screens.find(t=>t.entry)?.id||e.screens[0].id}function rn({project:e,children:t}){let n=Io(e),[r,o]=React.useState({mode:"canvas",viewportKey:e.defaultViewport,entryId:n,currentScreenId:n,history:[]}),a=React.useCallback(d=>{if(!e.screens.some(l=>l.id===d))throw new Error(`Navigation target "${d}" does not exist`);o(l=>{if(l.mode==="demo"&&d!==l.currentScreenId&&!e.screens.find(u=>u.id===l.currentScreenId).links.includes(d))throw new Error(`Screen "${l.currentScreenId}" links do not include "${d}"`);return{...l,currentScreenId:d,history:l.mode==="demo"&&d!==l.currentScreenId?[...l.history,l.currentScreenId]:l.history}})},[e]),i=React.useCallback(d=>{if(!e.screens.find(g=>g.id===d))throw new Error(`Navigation target "${d}" does not exist`);o(g=>({...g,entryId:d,currentScreenId:d,history:[]}))},[e]),f=React.useCallback(()=>{o(d=>d.history.length===0?d:{...d,currentScreenId:d.history[d.history.length-1],history:d.history.slice(0,-1)})},[]),m=React.useCallback(()=>{o(d=>({...d,currentScreenId:d.entryId,history:[]}))},[n]),v=React.useCallback(d=>{if(d!=="canvas"&&d!=="demo")throw new Error(`Unknown mode "${d}"`);o(l=>({...l,mode:d,history:[]}))},[]),p=React.useCallback(d=>{if(!e.screens.some(l=>l.id===d))throw new Error(`Navigation target "${d}" does not exist`);o(l=>({...l,mode:"demo",currentScreenId:d,history:[]}))},[e]),w=React.useCallback(d=>{if(!Object.hasOwn(e.viewports,d))throw new Error(`Unknown viewport "${d}"`);o(l=>({...l,viewportKey:d}))},[e]),h=React.useMemo(()=>({mode:r.mode,viewportKey:r.viewportKey,viewport:e.viewports[r.viewportKey],entryId:r.entryId,currentScreenId:r.currentScreenId,navigate:a,goBack:f,reset:m,selectEntry:i,setMode:v,enterDemo:p,setViewportKey:w,canGoBack:r.history.length>0}),[p,f,a,e,m,i,v,w,r]);return React.createElement(on.Provider,{value:h},t)}function we(){let e=React.useContext(on);if(!e)thr
...[truncated 28 chars]
Skill contains instructions that could directly expose system prompts, internal rules, or hidden instructions to users or external parties.
/* PREBUILT VUE GLOBAL POC BOARD BRIDGE. BUSINESS SCREENS REQUIRE NO BUILD. */
(()=>{var on=React.createContext(null);function Io(e){return e.screens.find(t=>t.entry)?.id||e.screens[0].id}function rn({project:e,children:t}){let n=Io(e),[r,o]=React.useState({mode:"canvas",viewportKey:e.defaultViewport,entryId:n,currentScreenId:n,history:[]}),a=React.useCallback(d=>{if(!e.screens.some(l=>l.id===d))throw new Error(`Navigation target "${d}" does not exist`);o(l=>{if(l.mode==="demo"&&d!==l.currentScreenId&&!e.screens.find(u=>u.id===l.currentScreenId).links.includes(d))throw new Error(`Screen "${l.currentScreenId}" links do not include "${d}"`);return{...l,currentScreenId:d,history:l.mode==="demo"&&d!==l.currentScreenId?[...l.history,l.currentScreenId]:l.history}})},[e]),i=React.useCallback(d=>{if(!e.screens.find(g=>g.id===d))throw new Error(`Navigation target "${d}" does not exist`);o(g=>({...g,entryId:d,currentScreenId:d,history:[]}))},[e]),f=React.useCallback(()=>{o(d=>d.history.length===0?d:{...d,currentScreenId:d.history[d.history.length-1],history:d.history.slice(0,-1)})},[]),m=React.useCallback(()=>{o(d=>({...d,currentScreenId:d.entryId,history:[]}))},[n]),v=React.useCallback(d=>{if(d!=="canvas"&&d!=="demo")throw new Error(`Unknown mode "${d}"`);o(l=>({...l,mode:d,history:[]}))},[]),p=React.useCallback(d=>{if(!e.screens.some(l=>l.id===d))throw new Error(`Navigation target "${d}" does not exist`);o(l=>({...l,mode:"demo",currentScreenId:d,history:[]}))},[e]),w=React.useCallback(d=>{if(!Object.hasOwn(e.viewports,d))throw new Error(`Unknown viewport "${d}"`);o(l=>({...l,viewportKey:d}))},[e]),h=React.useMemo(()=>({mode:r.mode,viewportKey:r.viewportKey,viewport:e.viewports[r.viewportKey],entryId:r.entryId,currentScreenId:r.currentScreenId,navigate:a,goBack:f,reset:m,selectEntry:i,setMode:v,enterDemo:p,setViewportKey:w,canGoBack:r.history.length>0}),[p,f,a,e,m,i,v,w,r]);return React.createElement(on.Provider,{value:h},t)}function we(){let e=React.useContext(on);if(!e)thr
...[truncated 28 chars]
Code contains obfuscation (base64, hex encoding with execution). This is often used to hide malicious functionality.
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */var r=function(A,e){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(A,e){A.__proto__=e}||function(A,e){for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&(A[t]=e[t])})(A,e)};function A(A,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function t(){this.constructor=A}r(A,e),A.prototype=null===e?Object.create(e):(t.prototype=e.prototype,new t)}var h=function(){return(h=Object.assign||function(A){for(var e,t=1,r=arguments.length;t<r;t++)for(var B in e=arguments[t])Object.prototype.hasOwnProperty.call(e,B)&&(A[B]=e[B]);return A}).apply(this,arguments)};function a(A,s,o,i){return new(o=o||Promise)(function(t,e){function r(A){try{n(i.next(A))}catch(A){e(A)}}function B(A){try{n(i.throw(A))}catch(A){e(A)}}function n(A){var e;A.done?t(A.value):((e=A.value)instanceof o?e:new o(function(A){A(e)})).then(r,B)}n((i=i.apply(A,s||[])).next())})}function H(t,r){var B,n,s,o={label:0,sent:function(){if(1&s[0])throw s[1];return s[1]},trys:[],ops:[]},A={next:e(0),throw:e(1),return:e(2)};return"function"==typeof Symbol&&(A[Symbol.iterator]=function(){return this}),A;function e(e){return function(A){return function(e){if(B)throw new TypeError("Generator is already executing.");for(;o;)try{if(B=1,n&&(s=2&e[0]?n.return:e[0]?n.throw||((s=n.return)&&s.call(n),0):n.next)&&!(s=s.call(n,e[1])).done)return s;switch(n=0,(e=s?[2&e[0],s.value]:e)[0]){case 0:case 1:s=e;break;case 4:return o.label++,{value:e[1],done:!1};case 5:o.label++,n=e[1],e=[0];continue;case 7:e=o.ops.pop(),o.trys.pop();continue;default:if(!(s=0<(s=o.trys).length&&s[s.length-1])&&(6===e[0]||2===e[0])){o=0;continue}if(3===e[0]&&(!s||e[1]>s[0]&&e[1]<s[3])){o.la
...[truncated 28 chars]
Code contains obfuscation (base64, hex encoding with execution). This is often used to hide malicious functionality.
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */var r=function(A,e){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(A,e){A.__proto__=e}||function(A,e){for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&(A[t]=e[t])})(A,e)};function A(A,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function t(){this.constructor=A}r(A,e),A.prototype=null===e?Object.create(e):(t.prototype=e.prototype,new t)}var h=function(){return(h=Object.assign||function(A){for(var e,t=1,r=arguments.length;t<r;t++)for(var B in e=arguments[t])Object.prototype.hasOwnProperty.call(e,B)&&(A[B]=e[B]);return A}).apply(this,arguments)};function a(A,s,o,i){return new(o=o||Promise)(function(t,e){function r(A){try{n(i.next(A))}catch(A){e(A)}}function B(A){try{n(i.throw(A))}catch(A){e(A)}}function n(A){var e;A.done?t(A.value):((e=A.value)instanceof o?e:new o(function(A){A(e)})).then(r,B)}n((i=i.apply(A,s||[])).next())})}function H(t,r){var B,n,s,o={label:0,sent:function(){if(1&s[0])throw s[1];return s[1]},trys:[],ops:[]},A={next:e(0),throw:e(1),return:e(2)};return"function"==typeof Symbol&&(A[Symbol.iterator]=function(){return this}),A;function e(e){return function(A){return function(e){if(B)throw new TypeError("Generator is already executing.");for(;o;)try{if(B=1,n&&(s=2&e[0]?n.return:e[0]?n.throw||((s=n.return)&&s.call(n),0):n.next)&&!(s=s.call(n,e[1])).done)return s;switch(n=0,(e=s?[2&e[0],s.value]:e)[0]){case 0:case 1:s=e;break;case 4:return o.label++,{value:e[1],done:!1};case 5:o.label++,n=e[1],e=[0];continue;case 7:e=o.ops.pop(),o.trys.pop();continue;default:if(!(s=0<(s=o.trys).length&&s[s.length-1])&&(6===e[0]||2===e[0])){o=0;continue}if(3===e[0]&&(!s||e[1]>s[0]&&e[1]<s[3])){o.la
...[truncated 28 chars]
Code contains obfuscation (base64, hex encoding with execution). This is often used to hide malicious functionality.
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */var r=function(A,e){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(A,e){A.__proto__=e}||function(A,e){for(var t in e)Object.prototype.hasOwnProperty.call(e,t)&&(A[t]=e[t])})(A,e)};function A(A,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function t(){this.constructor=A}r(A,e),A.prototype=null===e?Object.create(e):(t.prototype=e.prototype,new t)}var h=function(){return(h=Object.assign||function(A){for(var e,t=1,r=arguments.length;t<r;t++)for(var B in e=arguments[t])Object.prototype.hasOwnProperty.call(e,B)&&(A[B]=e[B]);return A}).apply(this,arguments)};function a(A,s,o,i){return new(o=o||Promise)(function(t,e){function r(A){try{n(i.next(A))}catch(A){e(A)}}function B(A){try{n(i.throw(A))}catch(A){e(A)}}function n(A){var e;A.done?t(A.value):((e=A.value)instanceof o?e:new o(function(A){A(e)})).then(r,B)}n((i=i.apply(A,s||[])).next())})}function H(t,r){var B,n,s,o={label:0,sent:function(){if(1&s[0])throw s[1];return s[1]},trys:[],ops:[]},A={next:e(0),throw:e(1),return:e(2)};return"function"==typeof Symbol&&(A[Symbol.iterator]=function(){return this}),A;function e(e){return function(A){return function(e){if(B)throw new TypeError("Generator is already executing.");for(;o;)try{if(B=1,n&&(s=2&e[0]?n.return:e[0]?n.throw||((s=n.return)&&s.call(n),0):n.next)&&!(s=s.call(n,e[1])).done)return s;switch(n=0,(e=s?[2&e[0],s.value]:e)[0]){case 0:case 1:s=e;break;case 4:return o.label++,{value:e[1],done:!1};case 5:o.label++,n=e[1],e=[0];continue;case 7:e=o.ops.pop(),o.trys.pop();continue;default:if(!(s=0<(s=o.trys).length&&s[s.length-1])&&(6===e[0]||2===e[0])){o=0;continue}if(3===e[0]&&(!s||e[1]>s[0]&&e[1]<s[3])){o.la
...[truncated 28 chars]
Detected: suspicious.dynamic_code_execution