create-pr — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited create-pr (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 2 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 2 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
CURRENT=$(git branch --show-current)
DEFAULT=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')$CURRENT equals $DEFAULT or is develop/release/*/hotfix/*: inform user they are on a protected branch, cannot create PR from heregit push -u origin $CURRENTDEFAULT=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')
git log --format="%s%n%b" "$DEFAULT..HEAD"
git diff --name-only "$DEFAULT..HEAD"
git diff --stat "$DEFAULT..HEAD"From the diff and commits, identify:
! in commits or BREAKING CHANGE footerTwo separate questions decide what the PR takes from an issue:
| Question | When yes |
|---|---|
| Belongs: does every change in the PR serve this one issue, and nothing else? | Copy the issue's labels, milestone and projects to the PR |
| Completes: once merged, is nothing left to do on the issue? | Link it under Development with a closing keyword |
A PR can belong to an issue without completing it: one step of a larger task. A PR that serves several issues, or mixes in unrelated changes, belongs to none of them and gets neither.
Take the first candidate found:
#123, owner/repo#123, or its URL.Closes #123, Fixes #123, Resolves #123.fix/123-null-user.gh issue view <number> --json number,title,state,body,labels,milestone,projectItemsAnswer both questions from the issue body and the change from Step 2. Ask the user when there are several candidates, the issue is closed, or either answer is unclear. A wrong "completes" closes the issue on merge. A non-GitHub key such as PROJ-456 carries no metadata; write it under Related Issues as plain text.
When the PR belongs to the issue:
projectItems only after checking the token: it comes back empty, without an error, when the token lacks the project scope. gh auth status --active --json hosts --jq '.hosts[][].scopes'Without project, skip projects and tell the user to run gh auth refresh -s project.
Under Related Issues, as plain text:
Never wrap the line, the keyword or the reference in backticks. GitHub does not parse a closing keyword inside a code span: the PR links nothing and merging closes nothing, with no error.
Conventional Commits format: <type>[scope]: <description>
git log --format="%s" -20)NEVER add task ID, issue number, or other metadata to the title:
❌ Wrong:
feat(messages): add server-only synthetic mailbox archive parser (BP-1234)✅ Correct:
feat(messages): add server-only synthetic mailbox archive parserOpen assets/pull_request_template.md and read it before writing a line of the body. That file is the only definition of the shape: reproduce every heading it carries verbatim, at the level and with the emoji it gives them, and fill each one. Add no section the template does not define.
Formatting rules:
path/to/file.ts\<br> in PR descriptions, so wrapping at ~80 chars creates visible artificial breaks. Let paragraphs flow; break only for new paragraphs, list items, or code blocksDo NOT reference specifications (./specs/*.md), plans (./plans/*.md), its section numbers, or TODO.md in pull request descriptions. These are internal artifacts for agent coordination and should not be exposed to human reviewers. If you need to explain a design decision, implementation detail, or rationale, do so in the description without citing internal documents. The description should be self-contained and understandable on its own.
Verify every claim about repository state before writing it. A diff supports claims about the change; it supports nothing about the environment the change lands in. The diff shows a workflow referencing CICDBOT_TOKEN - it says nothing about whether that secret exists. Writing "requires CICDBOT_TOKEN to be configured" silently promotes a reference into a missing prerequisite, and the reviewer goes chasing a risk that is not there.
Confirm with a command, or do not assert. When a check is unavailable, address the reviewer instead: "Confirm CICDBOT_TOKEN is set for this repo" is useful; "requires CICDBOT_TOKEN" is a guess wearing a warning's clothes.
| Claim | Check before writing it |
|---|---|
| A secret or variable exists | gh secret list, gh variable list |
| A branch rule or required status check is in force | gh api repos/{owner}/{repo}/rulesets |
| A person, bot, or team has access | gh api repos/{owner}/{repo}/collaborators |
| A repository setting or feature is enabled | gh api repos/{owner}/{repo} --jq '.<field>' |
| An external action, workflow, or tag is reachable | gh api repos/{owner}/{repo} |
| A CI job or workflow with a given name exists | Read .github/workflows/*.yml: jobs.<id>.name is the displayed job name. A step name is not a job name |
| A workflow runs on a given branch or event | Read the workflow's on: block. pull_request-only means the default branch is never checked |
This governs every section, not only Risk Assessment. An unverified line under "Sensitive Areas" costs the reviewer the same time.
Complexity guide:
| Level | Criteria |
|---|---|
| Low | Single file, config, docs, simple fix |
| Medium | Multiple related files, new feature with tests |
| High | Cross-cutting, migrations, breaking changes, security |
DEFAULT=$(gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name')
gh pr create \
--title '<title>' \
--body '<description>' \
--base "$DEFAULT"For drafts, add --draft.
When the PR belongs to an issue (Step 3), add one --label '<name>' per label and --milestone '<title>', omitting any that are empty. Add projects after creation, so that a project failure cannot block the PR:
gh pr edit <number> --add-project '<project title>'When updating an existing PR, apply the same metadata with gh pr edit --add-label, --milestone and --add-project.
MANDATORY: Use single quotes for --body to avoid shell interpolation. NEVER use double quotes, which can cause variables or special characters in the description to be misinterpreted by the shell.
gh pr view --webgh pr view --json labels,milestone,projectItems,closingIssuesReferencesWhen the PR completes an issue, closingIssuesReferences must list it. An empty list means the Related Issues line is malformed, most often a keyword in backticks: fix the body with gh pr edit and check again. It is not propagation delay.
Report: PR number, URL, title, base/head branches, and the issue metadata that was set. Name every field that could not be set, and why.
| Error | Fix |
|---|---|
| "pull request already exists" | gh pr view to see existing |
| "no commits between" | Verify branch has commits ahead of base |
| Auth failure | gh auth login --web |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.