Back to skill

Security audit

Horse Sticker Maker

Security checks for vulnerabilities and agentic risk

Overview

This skill is mostly a festive sticker web app, but it under-discloses server-side Google AI generation and exposes public endpoints that can spend the installer’s API quota.

Review this before installing or deploying. Do not deploy it with real Google API keys unless you add authentication, rate limiting, spend limits, provider disclosure, and a privacy notice for submitted names/text. Prefer a lockfile or npm ci, bundle or self-host gif.js with integrity controls, and remove unused AI endpoints if you only want a local GIF sticker maker.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
assets/horse-blessing-template/app/api/generate/route.ts:34
Finding

Unauthenticated Public Endpoints Can Consume Billable AI Resources

Content
View full analysis
10) { return NextResponse.json({ error: '请输入有效的名字(1-10个字)' }, { status: 400 }) } const trimmed = name.trim() const chars = Array.from(trimmed) const padded = chars.length >= 4 ? chars.slice(0, 4) : [...chars, ...['马', '到', '成', '功'].slice(0, 4 - chars.length)] // Prompt construction omitted here only for readability. const textRaw = await geminiGenerate(textPrompt) const jsonMatch = textRaw.match(/\{[\s\S]*\}/) if (!jsonMatch) throw new Error('文本生成格式错误') const textResult = JSON.parse(jsonMatch[0]) const imageBase64 = await imagenGenerate(imagePrompt) return NextResponse.json({ poem: textResult.poem, blessing: textResult.blessing, fortune: textResult.fortune || '马到成功', image: imageBase64 ? `data:image/png;base64,${imageBase64}` : null, }) } catch (e: any) { console.error('Generate error:', e) return NextResponse.json({ error: '生成失败,请重试: ' + e.message }, { status: 500 }) } } ``` `assets/horse-blessing-template/app/api/sticker/route.ts`: ```ts export async function POST(req: NextRequest) { try { const { text, styleId } = await req.json() if (!text || typeof text !== 'string' || text.trim().length === 0 || text.trim().length > 8) { return NextResponse.json({ error: '请输入1-8个字的表情文字' }, { status: 400 }) } const trimmed = text.trim() const styleDesc = STYLE_PROMPTS[styleId] || ST ...[truncated 2318 chars]
Remediation
View remediation

T03 · Remote Payload Retrieval and Execution

Error
Location
assets/horse-blessing-template/app/sticker/page.tsx:182
Finding

Unverified Third-Party JavaScript Is Executed at Runtime

Content
View full analysis
setGifReady(true)} /> ``` ### Technical Analysis The sticker page downloads and executes JavaScript from a third-party CDN whenever a user loads the page. Although the package version is specified, the response is not cryptographically verified with Subresource Integrity, and the project does not configure a restrictive Content Security Policy. Consequently, the code that executes in the browser can differ from the code reviewed in this project. A compromise of the CDN, package distribution account, DNS/TLS delivery path, or hosted artifact could substitute malicious JavaScript. The remote script executes in the application's page context and can interact with the DOM, monitor user interactions, make same-origin requests, and access any browser-side data available to that origin. ### Attack Path 1. The upstream package artifact or CDN delivery infrastructure is compromised. 2. The attacker replaces the expected `gif.js` response with modified JavaScript. 3. A user visits `/sticker`. 4. Next.js loads and executes the modified script in the application origin. 5. The malicious script reads page data, monitors input, invokes same-origin APIs, or sends captured information to an attacker-controlled endpoint. ### Impact Assessment Compromised remote code can obtain the privileges of client-side JavaScript running within the application's origin. Depending on the deployment's broader authentication and storage design, this may permit theft of non-HttpOnly browser data, modification of displayed content, monitoring of sticker text, unauthorized same-origin API requests, and user redirection. No compromise of the current CDN artifac ...[truncated 139 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
assets/horse-blessing-template/app/api/generate/route.ts:3
Finding

API Credential Is Embedded in Request URLs Sent to a Configurable Destination

Content
View full analysis
{ const res = await fetch(`${BASE}/gemini-2.5-flash:generateContent?key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ contents: [{ role: 'user', parts: [{ text: prompt }] }], generationConfig: { temperature: 0.9, maxOutputTokens: 2048, thinkingConfig: { thinkingBudget: 0 } }, }), }) const data = await res.json() if (data.error) throw new Error(data.error.message || 'Gemini API error') const candidates = Array.isArray(data) ? data[data.length - 1]?.candidates : data.candidates return candidates?.[0]?.content?.parts?.map((p: any) => p.text).join('') || '' } async function imagenGenerate(prompt: string): Promise { const res = await fetch(`${BASE}/imagen-4.0-generate-001:predict?key=${API_KEY}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ instances: [{ prompt }], parameters: { sampleCount: 1, aspectRatio: '9:16' }, }), }) ``` ### Technical Analysis The Google API key is included in the query string of outbound request URLs. URLs are more likely than authorization headers to be retained in proxy, gateway, observability, error, or diagnostic logs. The request destination is also controlled by the `GOOGLE_API_BASE` environment variable without validation or an allowlist. If deployment configuration is modified accidentally or maliciously, both the API key and generated prompt—including the name supplied by the user— ...[truncated 1416 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
assets/horse-blessing-template/package.json:8
Finding

Dependency Installation Is Not Reproducible or Cryptographically Locked

Content
View full analysis
/assets/horse-blessing-template ./horse-blessing cd horse-blessing npm install ``` `assets/horse-blessing-template/package.json`: ```json { "dependencies": { "gif-encoder-2": "^1.0.5", "html2canvas-pro": "^1.6.7", "next": "^14.0.0", "png-js": "^1.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "sharp": "^0.34.5" }, "devDependencies": { "@types/node": "^20.0.0", "@types/react": "^18.2.0", "autoprefixer": "^10.4.0", "postcss": "^8.4.0", "tailwindcss": "^3.4.0", "typescript": "^5.0.0" } } ``` ### Technical Analysis The project does not include a package lockfile, while most dependencies use compatible-version ranges. Following the documented `npm install` procedure can therefore resolve different direct and transitive package versions at different times. Installed packages may execute lifecycle scripts during installation. Without a reviewed lockfile, users cannot reliably reproduce the audited dependency graph or verify that installation will use the versions originally assessed. No currently declared package was established as malicious during this audit. The finding concerns avoidable supply-chain exposure and non-reproducible installation. ### Attack Path 1. A malicious or compromised release enters the version range permitted by `package.json`, or a transitive dependency resolves to a compromised release. 2. A user follows the documented `npm install` procedure. 3. npm resolves the newer dependency graph because no lockfile fixes reviewed versions and integrity hashes. 4. Malicious package code executes during installation, build time, or application runtime. 5. The package may access source files, environment variables, ...[truncated 543 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

A second description-behavior mismatch again points to undeclared external AI image generation and server-side processing despite the skill claiming fixed client-side gif.js rendering. Hidden remote generation increases risk because prompts or user content could be sent off-box unexpectedly, and operators may not apply the controls appropriate for a networked content-generation service.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

A second description-behavior mismatch again points to undeclared external AI image generation and server-side processing despite the skill claiming fixed client-side gif.js rendering. Hidden remote generation increases risk because prompts or user content could be sent off-box unexpectedly, and operators may not apply the controls appropriate for a networked content-generation service.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

A second description-behavior mismatch again points to undeclared external AI image generation and server-side processing despite the skill claiming fixed client-side gif.js rendering. Hidden remote generation increases risk because prompts or user content could be sent off-box unexpectedly, and operators may not apply the controls appropriate for a networked content-generation service.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill describes actions that involve network access, package installation, local execution, and deployment, but it does not declare any explicit tool scope or permissions boundaries. In an agent setting, this can cause over-broad execution authority, making it easier for the skill to reach external services or environment data without clear operator review.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The manifest describes a web app for generating horse-themed blessing stickers with client-side GIF rendering via gif.js, which implies local/browser-side composition of text and animation. This route adds server-side networked AI generation for both text and images using Google APIs, a materially broader behavior than the stated client-side sticker maker functionality.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

User-supplied names are embedded directly into prompts and transmitted to external Google APIs, which means potentially identifying personal data leaves the application boundary. In this skill context, users may reasonably expect a lightweight sticker generator, so undisclosed third-party transmission increases privacy risk and may violate consent, policy, or data-handling expectations.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Error messages and generation instructions are hard-coded in Chinese, and the model prompt requires Chinese poetic output, with no indication that users can opt into another language or that the skill is intentionally limited to a Chinese-only audience. This is a natural-language locale policy concern under the rule for forced language without user opt-in.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The endpoint sends user-supplied text to a third-party generative AI service without any visible consent, privacy notice, abuse controls, or request throttling. In the context of a sticker maker this network access is functionally related, but it still creates a real data-exposure and operational-risk surface because user input leaves the application boundary and the route can be abused to consume paid API quota.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The manifest describes a web app that supports Canvas-based client-side GIF rendering via gif.js, implying sticker generation happens in-browser from predefined animation assets. This route instead sends user input to Google's Gemini image-generation API and produces a server-generated single image, which is a materially different implementation and capability than the stated client-side GIF sticker maker.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The generated prompt requires Chinese-language text and a fixed Chinese slogan, and earlier style strings are also exclusively Chinese. This imposes a specific language/locale on users without any opt-in or documented region-specific justification, which matches the policy-violation criteria.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The save flow uses html2canvas to rasterize the rendered card and then calls canvas.toDataURL('image/png'), which creates a static PNG. That conflicts with the manifest’s claim of animated GIF sticker creation via gif.js and indicates materially different output behavior from the stated skill purpose.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This TypeScript/TSX file presents user-facing alerts, labels, buttons, and descriptive text entirely in Chinese, such as the failure alerts and all visible interface copy. Under the stated policy, forcing a specific language without offering user choice or documenting a justified locale restriction is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The manifest describes a Year-of-the-Horse animated GIF sticker maker with 6-frame horse animation, Canvas-based GIF rendering, and WeChat-compatible sticker generation. This page instead sends the user's name to '/api/generate' to obtain a poem, blessing, fortune, and optional image, then renders a blessing card and exports only a static PNG screenshot of that card.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
90% confidence
Finding

The stylesheet hard-codes 'PingFang SC' and 'Microsoft YaHei', which biases rendering toward Simplified Chinese locale conventions. The provided file contains no indication that this locale preference is optional or justified for a region-specific skill, so it may violate language/locale policy requirements.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The layout hard-codes the document language to "zh-CN", which imposes a specific language/locale on all users. The file does not indicate any user opt-in or justification that the skill is intended only for a China-specific audience.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

This code presents user-facing alerts, labels, button text, and help text exclusively in Chinese, including the fixed slogan text rendered into the sticker. That can violate language/locale policy when no user opt-in or alternate locale path is provided.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · assets/horse-blessing-template/package.json (reported line 11)May include surrounding context.

json
"start": "next start"
  },
  "dependencies": {
    "gif-encoder-2": "^1.0.5",
    "html2canvas-pro": "^1.6.7",
    "next": "^14.0.0",
    "png-js": "^1.0.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · assets/horse-blessing-template/package.json (reported line 12)May include surrounding context.

json
},
  "dependencies": {
    "gif-encoder-2": "^1.0.5",
    "html2canvas-pro": "^1.6.7",
    "next": "^14.0.0",
    "png-js": "^1.0.0",
    "react": "^18.2.0",

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · assets/horse-blessing-template/package.json (reported line 13)May include surrounding context.

json
"dependencies": {
    "gif-encoder-2": "^1.0.5",
    "html2canvas-pro": "^1.6.7",
    "next": "^14.0.0",
    "png-js": "^1.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",

Unverifiable Dependency: next has 16 known advisory(ies) (CVE-2025-30218 (Next.js may leak x-middleware-subrequest-id to external hosts); CVE-2021-43803 (Unexpected server crash in Next.js.); CVE-2026-44575 (Next.js has a Middleware / Proxy bypass in App Router applications via segment-p) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · assets/horse-blessing-template/package.json (reported line 14)May include surrounding context.

json
"gif-encoder-2": "^1.0.5",
    "html2canvas-pro": "^1.6.7",
    "next": "^14.0.0",
    "png-js": "^1.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "sharp": "^0.34.5"

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · assets/horse-blessing-template/package.json (reported line 15)May include surrounding context.

json
"html2canvas-pro": "^1.6.7",
    "next": "^14.0.0",
    "png-js": "^1.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "sharp": "^0.34.5"
  },

Unverifiable Dependency: react has 2 known advisory(ies) (CVE-2013-7035 (Cross-Site Scripting in react); GHSA-hg79-j56m-fxgv (Cross-Site Scripting in react)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependencies lack version pinning, allowing potential malicious package updates. Consider pinning versions.

Content

Scanner excerpt · assets/horse-blessing-template/package.json (reported line 16)May include surrounding context.

json
"next": "^14.0.0",
    "png-js": "^1.0.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "sharp": "^0.34.5"
  },
  "devDependencies": {

Unverifiable Dependency: react-dom has 1 known advisory(ies) (CVE-2018-6341 (Cross-Site Scripting in react-dom)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
40% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
assets/horse-blessing-template/app/api/generate/route.ts:3

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
assets/horse-blessing-template/app/api/sticker/route.ts:3