Back to skill

Security audit

edic-design-system

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent EDIC design-system helper, but its documentation encourages loading mutable remote JavaScript without integrity protection.

Install only if you are comfortable reviewing its generated web code. Prefer local, reviewed copies of EDIC assets or pin CDN URLs to immutable versions with SRI, and replace the toast example's innerHTML message insertion with textContent before using untrusted strings.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T03 · Remote Payload Retrieval and Execution

Error
Location
README.md:77
Finding
Mutable Remote JavaScript Is Loaded Without Integrity Verification<![CDATA[ ## Vulnerability Details **File Location**: `README.md`, lines 77–85 **Vulnerability Type**: Mutable remote payload retrieval and browser execution **Risk Level**: High ### Vulnerable Code ```html <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/cgartlab/edic-design-system@main/styles.css"> ... <script src="https://cdn.jsdelivr.net/gh/cgartlab/edic-design-system@main/scripts.js"> </script> ``` ### Technical Analysis The installation example instructs users to load executable JavaScript from the `main` branch of an external GitHub repository through jsDelivr. The `main` branch is mutable, so the content executed by users can change after this Skill package has been reviewed. The script URL is not pinned to a release version or immutable commit hash, and the `<script>` element has no Subresource Integrity (`integrity`) attribute. Consequently, neither the browser nor the reviewed package guarantees that the downloaded script is the version expected by the user. The referenced `scripts.js` is not included in the audited artifact. Its implementation and future behavior therefore cannot be verified from the supplied project. ### Attack Path 1. A user follows the installation example and includes the documented remote script. 2. An attacker compromises the upstream repository, a maintainer account, or another part of the remote delivery chain. 3. The attacker changes `scripts.js` on the mutable `main` branch. 4. jsDelivr serves the modified JavaScript under the unchanged URL. 5. The victim opens the affected page. 6. The browser executes the modified script in the page's origin and security context. ### Impact Assessment A malicious replacement script could obtain the same browser privileges as other first-party JavaScript on the consuming page. Depending on the application, this could permit: - Reading and modifying page content. - Capturing form values and other data accessible through the DOM. - Reading non-HttpOnly browser storage ...[truncated 324 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Include audited copies of `styles.css` and `scripts.js` directly in the Skill package and recommend local hosting. 2. If CDN delivery is necessary, pin each asset to an immutable release tag or, preferably, a specific commit hash rather than `@main`. 3. Publish cryptographic hashes and add Subresource Integrity verification: ```html <script src="https://cdn.example.invalid/edic/<immutable-version>/scripts.js" integrity="sha384-<verified-hash>" crossorigin="anonymous"> </script> ``` 4. Apply equivalent version pinning and integrity protection to the remote stylesheet. 5. Use a restrictive Content Security Policy that limits permitted script sources and prevents unapproved secondary payload loading. 6. Establish a release process that reviews, hashes, and signs browser assets before publication. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
references/EXAMPLES.md:143
Finding
DOM-Based Cross-Site Scripting in Toast Notification Example<![CDATA[ ## Vulnerability Details **File Location**: `references/EXAMPLES.md`, lines 143–151 **Vulnerability Type**: Unsafe insertion of untrusted data through `innerHTML` **Risk Level**: Medium ### Vulnerable Code ```js function showToast(message, type = '') { const group = document.querySelector('.ds-toast-group'); const toast = document.createElement('div'); toast.className = `ds-toast${type ? ' ds-toast--' + type : ''}`; toast.innerHTML = ` <svg class="ds-toast-icon" width="18" height="18" aria-hidden="true"> <use href="#icon-check-circle"></use> </svg> <span class="ds-toast-text">${message}</span> <button class="ds-toast-close" aria-label="关闭通知">×</button> `; ``` ### Technical Analysis The `message` parameter is interpolated directly into an HTML template and assigned to `toast.innerHTML`. No escaping, validation, or sanitization is performed. If a consuming application passes attacker-controlled data to `showToast`, the browser parses that data as markup rather than displaying it as text. An attacker can consequently inject elements with executable event handlers or other active HTML. Common sources of untrusted toast messages include query parameters, API error messages, uploaded filenames, form input, and chat content. The `type` parameter is also concatenated into a class name without allowlist validation. This is not independently demonstrated as script execution in the shown code, but validating it would reduce unintended styling and selector manipulation. ### Attack Path 1. An application adopts the documented `showToast` implementation. 2. The application passes untrusted content to the `message` parameter. 3. An attacker supplies a payload such as: ```html <img src=x onerror="alert(document.domain)"> ``` 4. The payload is interpolated into the template assigned to `toast.innerHTML`. 5. The browser creates the injected element. 6. Its error handler executes JavaScript in the consuming application's origin. ...[truncated 734 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Build the fixed markup with DOM APIs and assign untrusted messages through `textContent`: ```js function showToast(message, type = '') { const allowedTypes = new Set(['', 'success', 'warning', 'error']); const safeType = allowedTypes.has(type) ? type : ''; const group = document.querySelector('.ds-toast-group'); if (!group) return; const toast = document.createElement('div'); toast.className = `ds-toast${safeType ? ` ds-toast--${safeType}` : ''}`; const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); icon.setAttribute('class', 'ds-toast-icon'); icon.setAttribute('width', '18'); icon.setAttribute('height', '18'); icon.setAttribute('aria-hidden', 'true'); const text = document.createElement('span'); text.className = 'ds-toast-text'; text.textContent = String(message); const close = document.createElement('button'); close.className = 'ds-toast-close'; close.type = 'button'; close.setAttribute('aria-label', 'Close notification'); close.textContent = '×'; toast.append(icon, text, close); group.prepend(toast); } ``` Additional hardening measures: 1. Treat API responses, URL parameters, filenames, and user-provided strings as untrusted. 2. If rich HTML is an explicit requirement, sanitize it with a maintained allowlist-based HTML sanitizer before insertion. 3. Validate `type` against a fixed set of supported modifiers. 4. Add automated tests using HTML and event-handler payloads to verify that messages are rendered only as text. 5. Deploy a restrictive Content Security Policy as defense in depth; do not use it as a replacement for safe DOM construction. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (24)

Hidden Instructions

High
Category
Prompt Injection
Content
### ❌ Static inline `style=` attributes

```html
<!-- ❌ Wrong — static values bypass token system -->
<div style="padding: 16px; background: #fff; border-radius: 8px;">
```
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
```

```html
<!-- ✅ Correct — use component classes -->
<div class="ds-card">

<!-- ✅ Also correct — inline style only for genuinely dynamic values -->
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
backdrop-filter effect. `ds-glass-meta` lives **inside** `ds-glass-card` as the footer row.

```html
<!-- ✅ Correct: colored parent + card + inner meta -->
<div class="ds-glass-demo-bg">
  <div class="ds-glass-card">
    <span class="ds-badge ds-badge--accent">新</span>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
<svg width="20" height="20" aria-hidden="true"><!-- github icon --></svg>
      </a>
      <button class="ds-theme-toggle-btn" aria-label="切换主题" data-theme-mode="system">
        <svg width="18" height="18" aria-hidden="true"><!-- theme icon --></svg>
      </button>
      <a href="/downloads.html" class="ds-navbar-cta">下载</a>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
```html
<section class="ds-hero-section">
  <!-- Decorative background blobs (aria-hidden) -->
  <div class="ds-bg-blob ds-bg-blob--1" aria-hidden="true"></div>
  <div class="ds-bg-blob ds-bg-blob--2" aria-hidden="true"></div>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
</div>
  </header>

  <!-- Body: ds-prose handles paragraph, heading, list, code spacing -->
  <p>正文段落。<code>ds-prose</code> 自动控制行宽(65–75 字符),
  调整 h2/h3 间距,处理 CJK 标点。</p>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
</div>
  </header>

  <!-- Body: ds-prose handles paragraph, heading, list, code spacing -->
  <p>正文段落。<code>ds-prose</code> 自动控制行宽(65–75 字符),
  调整 h2/h3 间距,处理 CJK 标点。</p>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
<body>
  <a href="#ds-main" class="ds-skip">跳到主内容</a>

  <!-- Navbar (see EXAMPLES.md #3 for full structure) -->
  <nav class="ds-navbar" role="navigation" aria-label="主导航">
    <div class="ds-navbar-inner">
      <a href="/" class="ds-navbar-brand">EDIC</a>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
<!-- Wrap article + TOC in a grid -->
<div class="ds-wrapper" style="display:grid; grid-template-columns:1fr 240px; gap:var(--ds-space-16); align-items:start;">
  <article class="ds-prose" id="ds-main">
    <!-- Pattern 6 content here -->
  </article>

  <aside style="position:sticky; top:calc(var(--ds-space-16) + var(--ds-space-8))">
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Hidden Instructions

High
Category
Prompt Injection
Content
</div>
    </header>

    <!-- Summary -->
    <section class="ds-mb-8">
      <h2 class="ds-h4 ds-text-accent" style="text-transform:uppercase; letter-spacing:var(--ds-tracking-wider)">简介</h2>
      <p class="ds-mt-2">5 年前端开发经验,专注设计系统与组件库建设……</p>
Confidence
70% confidence
Finding
Hidden instructions were detected in comments or invisible text. These could contain malicious directives. Manual review is recommended.

Natural-Language Policy Violations

Medium
Confidence
81% confidence
Finding
The guidance suggests using "CJK 中文优先" so the AI will automatically choose corresponding components and tokens, but the document does not present alternative language or locale options for non-Chinese output. This can be read as steering the skill toward a specific locale by default rather than offering explicit user choice.

Skill Enumeration

Medium
Category
Agent Snooping
Content
```bash
# 项目级安装(推荐)
mkdir -p .claude/skills
# 解压本 ZIP,将 edic-design-system 目录内容放入 .claude/skills/edic-design-system/
# 或直接放置 SKILL.md 文件
Confidence
85% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Session Persistence

Medium
Category
Rogue Agent
Content
```bash
# 项目级安装(推荐)
mkdir -p .claude/skills
# 解压本 ZIP,将 edic-design-system 目录内容放入 .claude/skills/edic-design-system/
# 或直接放置 SKILL.md 文件
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Session Persistence

Medium
Category
Rogue Agent
Content
```bash
# 项目级安装(推荐)
mkdir -p .claude/skills
# 解压本 ZIP,将 edic-design-system 目录内容放入 .claude/skills/edic-design-system/
# 或直接放置 SKILL.md 文件
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Skill Enumeration

Medium
Category
Agent Snooping
Content
# 或直接放置 SKILL.md 文件

# 全局安装
mkdir -p ~/.claude/skills/edic-design-system
cp SKILL.md ~/.claude/skills/edic-design-system/
```
Confidence
85% confidence
Finding
Skill enumerates or reads other installed skills. Access to other skills' SKILL.md files or the skills directory reveals prompt instructions, capabilities, and secrets that should be invisible to peer skills.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The activation text says to use this skill whenever the user asks to build, style, or refactor anything for EDIC, or explicitly requests the EDIC / editorial-olive design system. That broad 'build/style/refactor anything' phrasing can cause the router or agent to invoke the skill for generic design tasks where the user did not clearly intend this specific constrained behavior, creating prompt-scope hijacking and policy bleed into unrelated requests.

Natural-Language Policy Violations

Medium
Confidence
91% confidence
Finding
The required skip-link text is hard-coded in Chinese ('跳到主内容') with no language negotiation or fallback. This can override the user's requested language or the document locale, producing inaccessible or misleading output in non-Chinese contexts and reducing usability for screen-reader users expecting localized navigation text.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This markdown file contains a hard-coded natural-language example using `aria-label="关闭"`, which imposes a specific language in the guidance. The file does not indicate that the skill is China-specific or that language should match user/project locale, so this conflicts with the language/locale policy criteria.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
This markdown file presents user-facing examples and labels in Chinese, starting with the title itself, without any indication that language selection is optional or that the file is intentionally region-specific. Under the natural-language policy rule, forcing a specific language without user opt-in is a policy concern.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The recipe hard-codes a Chinese locale (`lang="zh-CN"`) and Chinese UI copy as the default scaffold without checking the user's requested language or region. In an agent skill, this can override user intent, produce inaccessible or unsuitable output for other audiences, and create prompt-quality/safety issues when the skill is invoked in broader contexts.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This additional skeleton again fixes the document to `zh-CN` and Chinese-only content, reinforcing a behavior where generated artifacts ignore user locale unless manually rewritten. In skill ecosystems, forced locale/content can propagate incorrect outputs across pages and documents, especially for resumes or public-facing materials.

Natural-Language Policy Violations

Low
Confidence
95% confidence
Finding
This markdown file includes a complete HTML email skeleton with `lang="zh-CN"`, which imposes a specific locale in the provided pattern. The file does not indicate that this pattern is region-specific or that users should choose the language/locale appropriate to their audience, so it can conflict with language-choice policy expectations.

Natural-Language Policy Violations

Low
Confidence
88% confidence
Finding
The heading on L002 presents content in Chinese alongside English, but the file does not explain any language-selection policy or indicate that bilingual output is optional. Under the stated rule, forcing or prescribing a specific language/locale without user opt-in can be a natural-language policy concern.

Natural-Language Policy Violations

Low
Confidence
78% confidence
Finding
The font stacks repeatedly prioritize SC-specific fonts such as "Noto Serif SC", "Source Han Serif SC", "Noto Sans SC", and "Noto Sans Mono SC". In a shared design-token file, this can impose a locale-specific typography choice across consumers without any accompanying opt-in or explanation of why a Simplified Chinese locale is required.

Static analysis

No suspicious patterns detected.