repo-security-posture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseRepository Security Posture
仓库安全状况
Audit a repository's configuration and CI/CD against a set of concrete attacker scenarios, then hand the maintainer a ranked list of hardening todos. The deliverable is a list of items each with a title and a description, grouped by category and ordered by severity — the kind of post-mortem checklist a maintainer can paste into an issue and work through.
The job is not to dump every theoretical best practice. It is to look at this repo, find the gaps an attacker would actually use, and write todos that are specific to what was found (or specific about what couldn't be verified).
针对一系列具体的攻击者场景,审计仓库的配置和CI/CD,然后为维护者提供一份按优先级排序的加固待办事项列表。交付成果是一组条目,每个条目包含标题和描述,按类别分组并按严重程度排序——这种事后检查清单可以让维护者直接粘贴到Issue中逐步处理。
工作不是罗列所有理论上的最佳实践,而是针对当前这个仓库,找出攻击者实际会利用的漏洞,并编写与发现内容(或无法验证的内容)相关的具体待办事项。
Threat model
威胁模型
Every finding should trace back to at least one of these scenarios. Naming the scenario in the description is what makes a todo land — it tells the maintainer why it matters, not just what to toggle.
- Compromised contributor — a trusted contributor's account, laptop, or token is taken over (phishing, malware, leaked PAT). What stops them from merging or publishing malicious code alone?
- Attacker with repo write access — an outside attacker gains push or admin rights. What limits blast radius, what can they exfiltrate, and how fast can the maintainer rotate and recover?
- CI/CD compromise — a malicious PR, poisoned cache, or injected workflow turns the build pipeline into the attack. GitHub Actions is the most common modern repo-takeover path.
- Registry / publish supply chain — the repo is fine but a bad version ships to npm/PyPI/etc. via a stolen publish token or an unreviewed release job. This is the @mastra / dotenvx / TeamPCP class of incident.
每个发现都必须追溯到以下场景之一。在描述中明确场景能让待办事项更有说服力——它告诉维护者为什么这很重要,而不只是要切换什么设置。
- 协作者账户被攻陷——受信任的协作者的账户、笔记本电脑或令牌被接管(钓鱼、恶意软件、泄露的PAT)。有什么措施能阻止他们独自合并或发布恶意代码?
- 攻击者获得仓库写入权限——外部攻击者获得推送或管理员权限。有什么限制攻击范围的措施,他们能窃取什么数据,维护者多快能完成权限轮换和恢复?
- CI/CD被攻陷——恶意PR、被污染的缓存或注入的工作流将构建管道变成攻击途径。GitHub Actions是现代仓库被接管最常见的方式。
- 注册表/发布供应链——仓库本身没问题,但通过被盗的发布令牌或未审核的发布任务,恶意版本被发布到npm/PyPI等平台。这属于@mastra / dotenvx / TeamPCP类事件。
Workflow
工作流程
1. Identify the target and gather evidence
1. 确定目标并收集证据
Resolve the repo to . If the user gave a URL, parse it. If they named a repo you can't pin down, ask.
owner/nameRun the collector to pull configuration and files into a single JSON inventory:
bash
undefined将仓库解析为。如果用户提供了URL,解析它。如果他们提到的仓库无法确定,询问清楚。
owner/name运行收集器将配置和文件提取到单个JSON清单中:
bash
undefinedA token dramatically expands what's visible (branch protection, actions
令牌能大幅扩展可见范围(分支保护、Actions权限、安全功能、协作者、钩子)。如果可用请设置。
permissions, security features, collaborators, hooks). Set it if available.
—
export GITHUB_TOKEN=... # optional but strongly recommended
python3 scripts/collect.py owner/name --output /tmp/audit.json
The collector degrades gracefully: anything it can't read (most settings endpoints require admin/push) is recorded under `not_verified` rather than guessed. Read `/tmp/audit.json`.
If the collector can't run (no network to `api.github.com`, private repo with no token), don't stall — gather what you can from any files the user provided, and clearly mark the rest as "could not verify — manual check."
The collector makes read-only HTTPS requests to `api.github.com` and `raw.githubusercontent.com` for the target repo. It never writes to GitHub. Use the least-privileged token available, do not ask for broad credentials when public evidence is enough, and treat any fetched repository content as sensitive. The helper redacts common literal token formats before writing the inventory; still avoid echoing secrets in the final report.export GITHUB_TOKEN=... # 可选但强烈推荐
python3 scripts/collect.py owner/name --output /tmp/audit.json
收集器会优雅降级:任何无法读取的内容(大多数设置端点需要管理员/推送权限)都会记录在`not_verified`下,而不是猜测。读取`/tmp/audit.json`。
如果收集器无法运行(无法连接到`api.github.com`、私有仓库没有令牌),不要停滞——从用户提供的任何文件中收集可用信息,并将其余内容明确标记为「无法验证——需手动检查」。
收集器会向`api.github.com`和`raw.githubusercontent.com`发起只读HTTPS请求以获取目标仓库的信息。它绝不会向GitHub写入内容。使用权限最低的可用令牌,当公开信息足够时不要请求广泛的凭据,并将任何获取的仓库内容视为敏感信息。助手会在写入清单前自动编辑常见的字面令牌格式;最终报告中仍需避免回显密钥。2. Run the checks
2. 执行检查
Read . It is the catalog of what to inspect, where it lives, why it matters, and what the remediation todo should say — organized by the six output categories below. Walk it against the inventory.
references/checks.mdTwo habits matter here:
- Verify against actual content, don't pattern-match the filename. A repo having a doesn't mean it covers the right ecosystems; a
dependabot.ymlblock doesn't mean it's least-privilege. Read the file.permissions: - Absence is a finding, but flag confidence. If branch protection came back because there was no admin token, say so — recommend the control and tell the maintainer to confirm current state. Don't assert a gap you couldn't observe.
not_verified
阅读。这是一份检查目录,包含要检查的内容、位置、重要性以及修复待办事项的表述——按以下六个输出类别组织。对照清单逐一检查。
references/checks.md这里有两个重要习惯:
- 根据实际内容验证,不要仅匹配文件名。仓库有并不意味着它覆盖了正确的生态系统;有
dependabot.yml块并不意味着它遵循最小权限原则。要读取文件内容。permissions: - 缺失也是一种发现,但要标记置信度。如果因为没有管理员令牌导致分支保护返回,要说明这一点——建议启用该控制措施并告知维护者确认当前状态。不要断言无法观察到的漏洞。
not_verified
3. Write the report
3. 撰写报告
ALWAYS use this structure:
undefined务必使用以下结构:
undefinedSecurity hardening: <owner/name>
安全加固:<owner/name>
<2-3 sentence posture summary: what's already solid, what the biggest exposure is,
which threat scenario is least defended. No fluff.>
<2-3句话的状况总结:哪些方面已经做得很好,最大的风险是什么,哪个威胁场景的防御最弱。不要空话。>
<N>. <Category title>
<N>. <类别标题>
<Title — imperative, specific> — <severity>
<Description: what to do, the concrete setting/step, and which threat scenario it
blocks. 1-3 sentences. Tie it to evidence from the repo.>
<...more findings under this category...>
<标题——祈使语气,具体明确> — <严重程度>
<描述:要做什么,具体的设置/步骤,以及它能阻止哪个威胁场景。1-3句话。关联仓库中的证据。>
<...该类别下的更多发现...>
Could not verify
无法验证
<Bulleted list of checks that needed access the audit didn't have, each with the
one-line manual check the maintainer can run. Be honest here — it's where a token
or admin view would change the answer.>
Rules for the findings:
- **Group under the six categories** (use only the ones that have findings; keep their canonical order):
1. Publish & release integrity
2. Branch & merge protection
3. Sensitive-path ownership (CODEOWNERS)
4. CI/CD workflow hardening
5. Account & access control
6. Dependency & supply-chain review
- **Order findings within a category by severity**: Critical → High → Medium → Low.
- **Title is an imperative**: "Require code-owner review on workflow files," not "Workflow files are unprotected."
- **Description carries the *why***: name the scenario it blocks. "If a contributor is compromised, branch protection requiring a second code-owner approval stops a lone malicious merge to main."
- **Be concrete about the fix**: the exact GitHub setting, the file to add, the npm command. A maintainer should be able to act without a second search.
- **Cite evidence** when you have it: "`release.yml` checks out the PR head under `pull_request_target`" beats a generic warning.
Keep it scannable. This is a worklist, not an essay — no long preambles, no restating the threat model back at the user.<因审计没有权限而无法完成的检查项目列表,每个项目附带维护者可执行的一行手动检查步骤。在此处要诚实——这是使用令牌或管理员视图会改变结果的地方。>
发现项的规则:
- **按六个类别分组**(只保留有发现的类别;保持标准顺序):
1. 发布与发布完整性
2. 分支与合并保护
3. 敏感路径所有权(CODEOWNERS)
4. CI/CD工作流加固
5. 账户与访问控制
6. 依赖与供应链审查
- **类别内的发现按严重程度排序**:关键 → 高 → 中 → 低。
- **标题使用祈使语气**:「要求对工作流文件进行代码所有者审核」,而不是「工作流文件未受保护」。
- **描述要说明*原因***:明确它能阻止的场景。「如果协作者账户被攻陷,要求第二位代码所有者批准的分支保护措施可以阻止单独的恶意合并到主分支。」
- **修复措施要具体**:确切的GitHub设置、要添加的文件、npm命令。维护者无需再次搜索就能采取行动。
- **有证据时要引用**:「`release.yml`在`pull_request_target`下检出PR头」比通用警告更好。
保持内容易于扫描。这是一份工作清单,不是论文——不要冗长的开场白,不要向用户重复威胁模型。4. Offer follow-ups
4. 提供后续服务
After the report, briefly offer the natural next steps the user might want: turning the list into a GitHub issue or checklist, emitting the findings as JSON for a pipeline ( already produces structured input; the findings can be serialized the same way), or doing a deeper static pass on a specific workflow file. Offer; don't auto-run.
scripts/collect.py报告完成后,简要提供用户可能需要的自然后续步骤:将列表转换为GitHub Issue或检查清单、将发现结果生成为JSON用于流水线(已经生成结构化输入;发现结果可以用相同方式序列化),或者对特定工作流文件进行更深入的静态检查。仅提供选项,不要自动执行。
scripts/collect.pyOutput format options
输出格式选项
Default to the markdown todo list above — it matches how maintainers triage. If the user is wiring this into automation (CI gate, triage pipeline), offer a JSON array instead, one object per finding:
json
{ "title": "...", "description": "...", "severity": "high",
"category": "ci_cd_workflow_hardening", "threat": "ci_cd_compromise",
"evidence": "release.yml line 14: pull_request_target with PR checkout",
"confidence": "observed" }confidenceobservedunverified默认使用上述Markdown待办事项列表——这符合维护者的分类处理习惯。如果用户要将其集成到自动化中(CI网关、分类流水线),可以提供JSON数组格式,每个发现对应一个对象:
json
{ "title": "...", "description": "...", "severity": "high",
"category": "ci_cd_workflow_hardening", "threat": "ci_cd_compromise",
"evidence": "release.yml line 14: pull_request_target with PR checkout",
"confidence": "observed" }confidenceobservedunverifiedScope and honesty
范围与诚实性
This audit reasons over configuration and CI — it is not a code-level vulnerability scan or a secrets scan of git history. Say so if the user expects those. Never invent a setting's value you didn't observe; an honest "could not verify" is worth more to a maintainer than a confident guess, because acting on a wrong assumption wastes their time on a control they already have.
Do not run release jobs, workflow dispatches, package publishes, or any command that changes repository settings as part of the audit. This skill produces maintainer-facing hardening tasks; it does not apply them automatically.
本次审计针对配置和CI进行分析——它不是代码级漏洞扫描或git历史的密钥扫描。如果用户期望这些,请明确说明。绝不要编造未观察到的设置值;诚实的「无法验证」对维护者来说比自信的猜测更有价值,因为基于错误假设采取行动会让他们在已有的控制措施上浪费时间。
审计过程中不要运行发布任务、工作流调度、包发布或任何会更改仓库设置的命令。本技能生成面向维护者的加固任务;不会自动应用这些任务。