安全审计
- 作者仓库星标 430
- 作者更新于 实时读取
- 作者仓库 aeon
- 领域
- 安全 · dev
- 兼容 Agent
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- 信任分
- 94 / 100 · 已通过审计
- 作者 / 版本 / 许可
- @aaronjmars · 未声明 license
- Token 消耗评级
- 低消耗
- 接入复杂程度
- 需简单配置
- 是否需要外部 API Key
- 不需要
- 兼容的系统
- 未声明(默认跨平台)
- 底层运行要求
- 无特殊要求
- 文件与系统权限
-
- 只读
- 允许写入 / 修改
- Shell 执行
- 读取环境变量
- 网络行为
- 允许外网请求
- 安装命令数
- 26 条
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
---
name: Skill Security Scan
description: Audit skills, workflows, and companion scripts for injection, exfiltration, traversal, and promp…
category: 安全
runtime: 无特殊运行时
---
# Skill Security Scan 输出预览
## PART A: 任务判断
- 适用问题:安全审计、密钥扫描、权限检查或风险分析。
- 输入要求:目标材料、限制条件、期望输出和验收方式。
- 证据边界:围绕“Threat categories / Coverage / Inputs and state”读取原文规则,不把推断写成作者承诺。
## PART B: 执行结果
- **01** 任务判断:确认你的需求是否属于安全审计、密钥扫描、权限检查或风险分析,并标出输入、限制和预期结果。
- **02** 执行计划:优先按“Threat categories / Coverage / Inputs and state”拆成步骤,说明每一步会读取什么、修改什么、产出什么。
- **03** 交付结果:给出可复制的命令、文件改动、检查清单或内容草稿,并说明如何继续迭代。
- **04** 风险边界:结合 读取文件、写入/修改文件、执行终端命令、读取环境变量、会按任务需要访问外部网络、通常不需要额外 API Key 给出执行前确认项。
## Running Rules
- 读取文件、写入/修改文件、执行终端命令、读取环境变量;会按任务需要访问外部网络;通常不需要额外 API Key。
- 先小样例验证,再放大到真实任务。
- 交付时同时给结果、检查口径和下一步迭代建议。 原文没有稳定的斜杠命令要求。安装验证后通常全局生效,直接在对话里点名这个 Skill 并描述任务即可。
告诉 Agent 目标文件或材料、期望结果、不可改范围、是否允许联网或执行命令。本 Skill 的权限画像是:读取文件、写入/修改文件、执行终端命令、读取环境变量。
先用一个小任务确认它会围绕“Threat categories / Coverage / Inputs and state”工作;涉及文件或命令时,先看 diff、日志、预览或测试结果。
检查最终产物是否包含明确结果、必要证据和下一步动作;如果输出泛泛而谈,就补充输入、边界和验收标准后重跑。
---
name: Skill Security Scan
description: Audit skills, workflows, and companion scripts for injection, exfiltration, traversal, and promp…
category: 安全
source: aaronjmars/aeon
---
# Skill Security Scan
## 什么时候使用
- 把安全方向的常用动作沉淀成 Agent 可调用的技能 适合处理安全审计、密钥扫描、权限检查和风险分析,核心价值是把输入、判断、执行、验证和交付边界固定下来,避免 Agent 泛泛回答。 围绕 dev 组织上下文、步骤和验收口径;通常不需…
- 面向安全审计、密钥扫描、权限检查或风险分析,优先处理能明确输入、步骤和验收标准的工作。
## 需要提供什么
- 目标材料、目录范围、期望结果和不可改动内容。
- 是否允许联网、执行命令、读写文件或调用外部服务。
## 执行规则
- 围绕「Threat categories / Coverage / Inputs and state」组织步骤,不把推断写成作者事实。
- 读取文件、写入/修改文件、执行终端命令、读取环境变量;会按任务需要访问外部网络;通常不需要额外 API Key。
- 先跑小样例,确认结果可检查后再扩大任务范围。
## 输出要求
- 给出最终产物、关键证据、验证方式和下一步动作。
- 信息不足时标记 unknown,不编造命令、平台或依赖。 作者原文负责流程事实;仓库文件负责来源和命令;流狐只补充适用场景、限制和质量判断。
skill "Skill Security Scan" {
输入层 -> 用户目标 + 目标文件 + 禁止范围 + 验收标准
上下文层 -> Threat categories / Coverage / Inputs and state
规则层 -> SKILL.md 触发条件 / 执行顺序 / 输出格式
运行层 -> 无特殊运行时 | 读取文件、写入/修改文件、执行终端命令、读取环境变量 | 会按任务需要访问外部网络
安全层 -> 通常不需要额外 API Key + 小任务验证 + diff / 日志复核
输出层 -> 可复制结果 + 检查清单 + 下一步迭代
} ${var} — a SKILL.md path, a skill name (e.g.
token-movers), or a directory. Empty = full corpus scan.
Today is ${today}. Audit the codebase for security risks in skill instructions, CI workflows, and companion scripts before they run.
Threat categories
Files instruct Claude Code and GitHub Actions runners to take actions. Adversarial or sloppy files can:
- Shell injection — unquoted variable expansion,
eval, backticks,$(...)in bash blocks - Secret exfiltration — env vars or file contents piped into outbound HTTP requests
- GitHub Actions script injection — user-controlled template expressions (
${{ github.event.* }}, PR titles, issue bodies, incoming messages) interpolated directly intorun:blocks (see the 2026-04-11messages.ymlincident inarticles/workflow-security-audit-2026-04-11.mdfor the canonical pattern and fix) - Path traversal — access files outside repo via
../..chains or absolute paths - Prompt override — instructions in fetched content or skill bodies attempting to make the agent disregard prior guidance, switch persona, or act on new "system" rules
- Destructive commands — irreversible ops like recursive deletes from root, device writes, forced pushes to main
- Obfuscation (2026 additions) — zero-width Unicode (U+200B, U+FEFF), bidi override (U+202E / Trojan Source), base64-decoded payloads,
fromCharCode, hex-escaped command strings, webhook SSRF hosts (ngrok, interact.sh, webhook.site, burpcollaborator, pipedream, requestbin)
Coverage
Scan every run:
skills/*/SKILL.md(primary)skills/*/*.shandskills/*/*.py(companion scripts that skills invoke).github/workflows/*.yml(CI — especiallyrun:blocks referencing${{ ... }})scripts/*.sh(repo-level scripts)
When ${var} is set:
- If it matches an existing SKILL.md path (absolute or relative) → scan that file only
- Else if a directory exists at
skills/${var}/→ scan everything under it - Else if it looks like a bare skill name and
skills/${var}/SKILL.mdexists → scan that file - Else abort with
ERROR: scope not found for var=${var}
Inputs and state
| Path | Purpose |
|---|---|
skills/skill-security-scan/scan.sh |
Raw regex scanner (HIGH/MEDIUM/LOW pattern library) |
skills/security/trusted-sources.txt |
GitHub owners/repos whose skills get format-only scans |
skills/security/scan-baseline.yml |
Human-reviewed-as-safe suppressions (bootstrap if missing) |
memory/state/security-scan.json |
Prior scan snapshot — used for delta |
memory/issues/INDEX.md |
Open/resolved issue index (HIGH findings file here) |
articles/security-scan-${today}.md |
Report output (only written if there are findings or a delta) |
Baseline file format
skills/security/scan-baseline.yml:
# Each entry suppresses a specific (file, line_range, pattern) match that a human has reviewed.
# Format:
# - file: <path>
# pattern: <regex pattern from scan.sh HIGH_PATTERNS/MEDIUM_PATTERNS/LOW_PATTERNS>
# lines: "15-25" # optional line range; omit to suppress across whole file
# reason: "documentation in threat model section"
# reviewed_by: "aaronjmars"
# reviewed_at: "2026-04-20"
suppressions: []
Seed suppressions at bootstrap with the self-documenting matches that we already know are false positives:
skills/skill-security-scan/SKILL.md— all prompt-override pattern matches inside the "Threat categories" section (documentation, not payload)skills/security-digest/SKILL.md— any curl/token pattern inside fenced code blocks showing example usage
Steps
Read memory. Read
memory/MEMORY.mdand today'smemory/logs/${today}.md(create if missing) for context.Bootstrap baseline. If
skills/security/scan-baseline.ymldoes not exist, create it with the seed suppressions listed above and recordBASELINE_BOOTSTRAPPEDin the exit status.Resolve scope per the
${var}rules above. Log the chosen scope.Preflight scanner. Verify
skills/skill-security-scan/scan.shis present and executable. If missing (sandbox edge case), fall back to inline Grep using the same HIGH/MEDIUM/LOW pattern library defined inscan.sh— never silently skip.Run scanner in JSON mode — invoke
scan.sh --json(or--all --jsonfor the full corpus) and capture the structured output:[{skill, status, file, high, medium, low}, ...]. Do not parse stderr into findings.Trusted-source filter. Load
skills/security/trusted-sources.txt. For each scanned file, check if the skill directory has anorigin:field in its frontmatter, or fall back to the repo's git remote. If the source is trusted (owner or owner/repo match), downgrade to format-only validation: verify frontmatter hasname,description,tags, and avarkey — emit no HIGH/MEDIUM/LOW findings for trusted sources, only format errors.Code-fence downgrade. For each non-trusted finding, re-read the file around the finding's line. If the line is inside a fenced code block (between
```markers in a Markdown file, or inside arun: |/script: |YAML block in a workflow file that is clearly an example, not an executable step), downgrade severity by one tier (HIGH → MEDIUM, MEDIUM → LOW, LOW → drop). Never downgrade inside actualrun:steps in real workflow files — those execute.Apply baseline suppression. Drop any finding whose (file, pattern, line) tuple is in
skills/security/scan-baseline.yml.Compute delta against
memory/state/security-scan.json(previous run's finding set, keyed bysha256(file+line_content+pattern)):- NEW — findings present now but not last run
- RESOLVED — findings present last run but gone now
- PERSISTENT — findings in both runs (not re-notified, but still counted)
File/close issues in
memory/issues/:- For each NEW HIGH finding (post-suppression): create
memory/issues/ISS-{next_id}.mdwith YAML frontmatter (id,title,status: open,severity: high,category: quality-regression,detected_by: skill-security-scan,detected_at: ${today},affected_skills) and append a row toINDEX.mdunder## Open. - For each RESOLVED finding that corresponds to an open ISS filed by
skill-security-scan: setstatus: resolved,resolved_at: ${today}, move the row from## Opento## ResolvedinINDEX.md. - Do NOT file issues for NEW MEDIUM or LOW findings — those live in the article report only.
- For each NEW HIGH finding (post-suppression): create
Write the report to
articles/security-scan-${today}.mdonly if there are any NEW, RESOLVED, or current HIGH findings. Structure:# Security Scan — ${today} **Verdict:** [CLEAN | ATTENTION | DEGRADED] **Scope:** [full corpus | ${var}] **Counts:** N files scanned · H HIGH · M MEDIUM · L LOW · X new · Y resolved since last scan ## Needs attention (NEW high-severity this run) For each: file:line, pattern that matched, one-line remediation snippet (see table below). ## Resolved since last scan List of findings that disappeared — good for confirming fixes. ## Persistent findings (unchanged) Count per severity; full list only in the appendix. ## Per-file results Table: file, status (PASS/WARN/FAIL), HIGH count, MEDIUM count, LOW count. ## Appendix — all current findings Full structured dump.Remediation snippets. For each HIGH finding, attach a one-line fix hint keyed off the pattern. Map (non-exhaustive — extend as new patterns are added to
scan.sh):Pattern category Remediation Shell eval / backticks / $(...)with variableQuote the variable; prefer ${VAR}with explicit quoting; replaceevalwith a functioncurl/wgetwith an env var in the URL or bodyMove secret into a pre-fetch script (see CLAUDE.mdSandbox section); never interpolate secrets into shell-block strings${{ github.event.* }}inside arun:blockRebind the value to an env:key first, then read$_SAFE_NAMEfrom the shell (seearticles/workflow-security-audit-2026-04-11.md)Path-traversal sequence Validate input against skills/*/or explicit allow-list; reject absolute pathsPrompt-override phrasing If the string is documentation, add a baseline suppression entry; if it's a payload, delete it Recursive delete rooted at /or~Scope to $REPO_ROOTor a specific subdir; never take a variable as the delete rootForce-push to main Remove the option or gate behind explicit human dispatch Obfuscation (zero-width / bidi / base64-decode pipe) Delete unless there's a documented, reviewed reason Persist state. Write the full current finding set to
memory/state/security-scan.jsonso the next run can compute delta. Include{generated_at, scope, findings: [{file, line, pattern, severity, fingerprint}]}.Notify via
./notifyonly when there is something new for the operator:- If any NEW HIGH finding → one paragraph summary naming affected skill(s), finding count, and path to the report.
- If any RESOLVED HIGH finding (but no new HIGH) → short "Resolved: X HIGH findings cleared since last scan."
- If only MEDIUM/LOW changes → skip notification (report is written, operator reads on demand).
- If no findings and no delta → skip notification; emit
SECURITY_SCAN_OKto stdout so heartbeat can log it.
Log to
memory/logs/${today}.mdwith an### skill-security-scansection: scope, exit status code, counts by severity, new/resolved counts, PR/issue IDs filed, report path.
Exit status codes
Emit exactly one to stdout (on its own line) before normal output:
SECURITY_SCAN_OK— no findings after suppression, no deltaSECURITY_SCAN_NEW— at least one NEW HIGH findingSECURITY_SCAN_RESOLVED— no new HIGH findings, but at least one was resolvedSECURITY_SCAN_NOCHANGE— findings exist but identical to last runSECURITY_SCAN_BOOTSTRAPPED— baseline file was just created; this run writes initial stateSECURITY_SCAN_ERROR— scope unresolvable, scanner missing, or write failure
Constraints
- Never auto-delete a finding from
scan-baseline.yml. Suppression is a human decision; the skill only adds seed entries on first bootstrap. - Never file an issue for a finding that is already represented by an open ISS (match by fingerprint — file+line+pattern).
- Never change
scan.sh's pattern library from inside this skill. Pattern evolution happens in a separate, reviewed PR. - Never notify on a pure no-op week. Silence is correct when nothing has changed.
- Treat trusted-sources downgrades as opt-in only — never trust a source not explicitly listed.
Sandbox note
This skill reads local files and shells out to scan.sh; no network calls required. If scan.sh is unavailable, perform the scan inline using Grep with the same pattern library — never silently skip. The ./notify call is covered by the standard post-processor (see CLAUDE.md Sandbox section).
先判断是否适合
作者设计意图
作者的方法与取舍
边界和复核