Back to skill

Security audit

Changelist Adoption

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly a coherent changelist/documentation workflow, but it asks agents to persist new repository rules that can override an existing “commit only when asked” policy and allow future auto-commits.

Install only if you deliberately want repository-level changelist rules to persist for future agent sessions. Before adopting it, remove or rewrite the auto-commit override so existing commit-authorization rules always win, and prefer a pinned installer or manual copy over `npx ...@latest`.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T02 · Agent Memory Poisoning

Error
Location
SKILL.md:46
Finding

Persistent Agent Rules Override Explicit Commit Authorization

Content
View full analysis

Vulnerability Details

File Location: SKILL.md:46-47; references/agents-rules-template.md:8; references/agents-rules-template.md:34-40
Vulnerability Type: Persistent Agent policy poisoning and authorization bypass
Risk Level: Critical

Vulnerable Code Snippets

SKILL.md:46-47:

markdown
4. **Write the rules into the instruction file** from `references/agents-rules-template.md`, adapting everything listed in step 1. If the target already has a "commit only when asked" policy, the pasted block must state its precedence explicitly, e.g. in a dedicated section that overrides the general policy. For multi-person repos, also fix the author-identity convention now (see Multi-person collaboration).

references/agents-rules-template.md:8:

markdown
- Commit policy — if the project's general policy is "commit only when asked", place this block in its own section and state that it overrides the general policy; otherwise drop the auto-commit bullets.

references/agents-rules-template.md:34-40:

markdown
### Auto-commit (if the project adopts it)

- After the entry is written, auto-commit to the current branch: code + tests + entry + index in one commit.
- Explicit pathspec only, never `git add -A`; stop and report if intended files contain unrelated changes.
- No AI attribution trailers in commit messages.

Technical Analysis

The bootstrap workflow directs the Agent to write rules into persistent repository instruction files such as AGENTS.md or CLAUDE.md. It specifically instructs the inserted rules to take precedence over an existing policy requiring commits to occur only when explicitly requested.

This changes behavior beyond the current Skill invocation. Future Agent sessions that load the repository instructions can automatically commit code, tests, changelist entries, and index changes without obtaining task-specific authorization. Although explicit pathspecs reduce accidental staging, they do not address t ...[truncated 1796 chars]

Remediation
View remediation

Remediation Suggestions

  1. Remove all instructions that override an existing “commit only when asked” or equivalent authorization policy.
  2. Establish explicit precedence in the opposite direction: repository and user authorization requirements must always override changelist automation.
  3. Require affirmative, task-specific user approval before every git commit.
  4. Make the default workflow stop after creating and validating the changelist files.
  5. Treat auto-commit as an optional mode that can only be enabled by an explicit user request for the current task, not through persistent bootstrap rules.
  6. Add safe replacement language such as:
markdown
- Never commit automatically.
- After verification and changelist updates, report the files ready to commit.
- Run `git commit` only after the user explicitly authorizes that commit.
- Existing repository commit-authorization policies always take precedence.
  1. During bootstrap, show the proposed persistent instruction changes to the user and obtain approval before writing them.
  2. Add tests or policy checks ensuring generated instruction blocks never weaken existing authorization constraints.

T08 · Insecure Dependencies

Warning
Location
README.md:18
Finding

Unpinned Third-Party Package Is Downloaded and Executed During Installation

Content
View full analysis

Vulnerability Details

File Location: README.md:18
Vulnerability Type: Unpinned executable dependency and supply-chain exposure
Risk Level: Medium

Vulnerable Code Snippet

bash
npx clawhub@latest install falllee/changelist-adoption

Technical Analysis

The documented installation command invokes npx with the mutable latest tag. npx may download and execute package code from the configured package registry. Because neither an immutable package version nor an integrity value is specified, the code executed by this command can change after the Skill has been audited.

The audited project does not itself contain a remote payload downloader. The risk arises from recommending an installation path that executes an unaudited future release of a third-party package.

Attack Path

  1. An attacker compromises the package publisher, registry account, release pipeline, or a transitive dependency used by a future clawhub release.
  2. The attacker publishes a malicious release and assigns or causes the latest tag to resolve to it.
  3. A user follows the installation command in README.md.
  4. npx retrieves the mutable package version from the registry.
  5. The downloaded package executes with the permissions of the user running the command.
  6. Malicious package code can access files, credentials, repositories, and network resources available to that user.

Impact Assessment

The possible impact is determined by the privileges of the user running npx. A compromised package could potentially:

  • Read or alter repositories and user files.
  • Access environment variables and locally available credentials.
  • Install additional packages or persistence mechanisms.
  • Execute arbitrary processes.
  • Send accessible information to external systems.

No evidence shows that the currently referenced package is malicious. The confirmed issue is the absence of version and integrity pinning for executable third-party installation code.

Remediation
View remediation

Remediation Suggestions

  1. Replace @latest with an exact, audited version:
bash
npx clawhub@1.2.3 install falllee/changelist-adoption
  1. Publish and document the expected package integrity hash or signed provenance.
  2. Recommend verifying package metadata, publisher identity, and integrity before execution.
  3. Prefer a non-executing installation option, such as downloading a versioned archive and verifying its checksum before copying files.
  4. Pin transitive dependencies in the installer and use lockfiles with integrity metadata.
  5. Document a trusted registry explicitly where appropriate.
  6. Periodically audit the exact pinned installer release before updating the documented version.

T09 · Insecure Skill Coding Practices

Note
Location
scripts/verify-index.mjs:15
Finding

Changelist Verifier Accepts Traversal Paths Outside the Intended Root

Content
View full analysis

Vulnerability Details

File Location: scripts/verify-index.mjs:15-25
Vulnerability Type: Path traversal and incomplete integrity validation
Risk Level: Low

Vulnerable Code Snippet

javascript
const linked = [...readme.matchAll(/\]\((\d{8}\/[^)#?]+\.md)\)/g)].map((m) => m[1]);
const onDisk = [];
for (const dir of fs.readdirSync(root)) {
  if (!/^\d{8}$/.test(dir) || !fs.statSync(path.join(root, dir)).isDirectory()) continue;
  for (const file of fs.readdirSync(path.join(root, dir))) {
    if (file.endsWith('.md')) onDisk.push(`${dir}/${file}`);
  }
}
const missing = linked.filter((l) => !fs.existsSync(path.join(root, l)));
const orphans = onDisk.filter((f) => !linked.includes(f));
const dupes = linked.filter((l, i) => linked.indexOf(l) !== i);
console.log(`linked ${linked.length}, onDisk ${onDisk.length}`);

The resulting exit condition is:

javascript
process.exit(missing.length || orphans.length || dupes.length ? 1 : 0);

Technical Analysis

The link-matching expression requires a path to begin with eight digits and end with .md, but the middle portion permits directory traversal segments such as ../. The verifier then passes the untrusted captured path to path.join(root, l). Node.js normalizes traversal segments, and the script does not verify that the resolved path remains inside the changelist root.

For example, a link resembling the following can resolve outside the intended directory:

markdown
[external file](20260101/../../outside.md)

The script only checks whether the normalized target exists. It does not reject traversal, symbolic-link escapes, or targets outside the root. It also prints the linked and on-disk counts without directly requiring equality. Consequently, an empty changelist tree with one traversal link to an existing external Markdown file can produce no missing files, no orphans, and no duplicates, resulting in exit code zero despite the count mismatch.

The script does not read or ex ...[truncated 1478 chars]

Remediation
View remediation

Remediation Suggestions

  1. Resolve the root to an absolute canonical path:
javascript
const resolvedRoot = fs.realpathSync(root);
  1. Reject absolute paths, . components, and .. components before performing filesystem checks.
  2. Resolve every linked target and verify containment:
javascript
function resolveContainedTarget(relativeTarget) {
  if (path.isAbsolute(relativeTarget)) {
    throw new Error(`absolute path is not allowed: ${relativeTarget}`);
  }

  const parts = relativeTarget.split(/[\\/]/);
  if (parts.some((part) => part === '..' || part === '.')) {
    throw new Error(`path traversal is not allowed: ${relativeTarget}`);
  }

  const target = path.resolve(resolvedRoot, relativeTarget);
  if (target !== resolvedRoot && !target.startsWith(`${resolvedRoot}${path.sep}`)) {
    throw new Error(`target escapes changelist root: ${relativeTarget}`);
  }

  return target;
}
  1. If symbolic links are permitted, compare fs.realpathSync(target) against the canonical root before accepting the target. Otherwise, reject symbolic links explicitly.
  2. Require exact count equality in the exit condition:
javascript
const countMismatch = linked.length !== onDisk.length;
process.exit(
  missing.length || orphans.length || dupes.length || countMismatch ? 1 : 0
);
  1. Validate the complete expected entry-path grammar, including a strict filename policy such as kebab-case names.
  2. Add regression tests for traversal paths, absolute paths, backslash traversal, symbolic-link escapes, duplicate links, orphan files, and linked/on-disk count mismatches.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Rogue AgentSelf-Modification, Session Persistence
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (5)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 82)May include surrounding context.

md
The skill directory is self-contained: `SKILL.md` plus `references/`, `assets/`, and `scripts/`. Install it in the repository that should adopt the practice at

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 156)May include surrounding context.

md
The skill directory is self-contained: `SKILL.md` plus `references/`, `assets/`, and `scripts/`. Install it in the repository that should adopt the practice at

Rp1

Medium
Category
MCP Rug Pull
Confidence
89% confidence
Finding

The README instructs users to execute npx clawhub@latest install ..., which fetches and runs the latest package version at execution time rather than a reviewed, pinned release. That creates a supply-chain risk: if the package is compromised or a breaking/malicious version is published later, users following the documentation may execute attacker-controlled code on their system.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
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.

Content

Scanner excerpt · SKILL.md (reported line 36)May include surrounding context.

md
1. **Survey the target repo first.** Read its agent instruction file(s) and docs layout, and check how it runs tests and commits. Never paste the rule template verbatim: adapt paths, language (match the project's docs language), commit policy, and the definition of "verified" (if the project has no tests, define the strongest verification it actually supports and name it explicitly in the rules).
2. **Design the module taxonomy from the real architecture.** Derive 5–12 top-level modules from the source tree — services, plugins, channels, UI, infra, whatever that project actually has — not from generic guesses. Two levels max (module > submodule). Seed only modules you expect to fill; the taxonomy grows by rule when entries don't fit, never by speculation.
3. **Create the index skeleton** from `assets/index-template.md` at `docs/changelist/README.md` (or the target's docs-root equivalent): header with a stats line and the maintenance rules, then the module tree.
4. **Write the rules into the instruction file** from `references/agents-rules-template.md`, adapting everything listed in step 1. If the target already has a "commit only when asked" policy, the pasted block must state its precedence explicitly, e.g. in a dedicated section that overrides the general policy. For multi-person repos, also fix the author-identity convention now (see Multi-person collaboration).
5. **Backfill only on request.** Classifying git history into entries is expensive and usually low value; do not invent entries for past work from `git log` alone. If the project already has scattered change records (docs/, wiki exports, old notes), classify those into the index and verify links.
6. **Verify** with `scripts/verify-index.mjs` (see Verification), then commit per the target's policy.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
93% confidence
Finding

The instruction "Pick ONE language variant" imposes a language/locale choice in the template workflow. Under the policy, forcing a specific language without explicit user opt-in or justification is a natural-language policy concern, and this file does not document a required locale-specific constraint.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.