Skip to content

bug: Security Issue, It is scanned by claude opus 5 #656

Description

@tuanquynet

What happened?

Findings

[VULN-001] Git Flag / Argument Injection in getChangedFiles (High)

  • Location: understand-anything-plugin/packages/core/src/staleness.ts:370
  • Confidence: High
  • Issue: getChangedFiles() executes git diff ${lastCommitHash}..HEAD --name-only via execFileSync without revision verification (git rev-parse) or --end-of-options separation.
  • Impact: When analyzing a project containing malicious graph metadata (e.g. knowledge-graph.json or meta.json where project.gitCommitHash is set to --output=path/to/target), git diff interprets the
    prefix as command options. Specifically, --output= causes Git to write arbitrary diff output to an attacker-controlled destination, resulting in arbitrary file creation or file overwrite.
  • Evidence:

// understand-anything-plugin/packages/core/src/staleness.ts:365-378
export function getChangedFiles(
projectDir: string,
lastCommitHash: string,
): string[] {
try {
const output = execFileSync("git", ["diff", ${lastCommitHash}..HEAD, "--name-only"], {
cwd: projectDir,
encoding: "utf-8",
});
return parseChangedFiles(output);
} catch {
return [];
}
}

(Note: In contrast, evaluateGraphFreshness at lines 223–229 in the same file safely validates the revision using ["rev-parse", "--verify", "--end-of-options", ${requestedGraphCommitHash}^{commit}]
before diffing).
- Fix: Verify and resolve lastCommitHash to a valid commit hash using rev-parse --verify --end-of-options and pass --end-of-options before the revisions:
```typescript
export function getChangedFiles(
projectDir: string,
lastCommitHash: string,
): string[] {
try {
 const commit = execFileSync(
   "git",
   ["rev-parse", "--verify", "--end-of-options", `${lastCommitHash}^{commit}`],
   { cwd: projectDir, encoding: "utf-8" },
 ).trim();
 const output = execFileSync(
   "git",
   ["diff", "--end-of-options", `${commit}..HEAD`, "--name-only"],
   { cwd: projectDir, encoding: "utf-8" },
 );
 return parseChangedFiles(output);
} catch {
 return [];
}
}

────────────────────────────────────────────────────────────────────────────────

[VULN-002] Unsanitized Commit Hash in /understand Skill Diff Commands (High)

  • Location: understand-anything-plugin/skills/understand/SKILL.md:196, understand-anything-plugin/skills/understand/SKILL.md:365, understand-anything-plugin/hooks/auto-update-prompt.md:28
  • Confidence: High
  • Issue: /understand instructions in SKILL.md and the auto-update hook prompt instruct the LLM / shell to directly interpolate into git diff ..HEAD --name-only
    without first resolving and sanitizing the commit hash with git rev-parse.
  • Impact: If a repository contains an attacker-controlled .ua/meta.json or .understand-anything/meta.json with a malicious gitCommitHash, executing the instructed command leads to Git flag injection
    or unexpected argument parsing during incremental analysis.
  • Evidence:

skills/understand/SKILL.md:196 & 365

git diff ..HEAD --name-only
git diff "..HEAD" --name-only > "$UA_DIR/tmp/changed-files.txt"

hooks/auto-update-prompt.md:28

git diff "..HEAD" --name-only

(Note: Other skills in the repository like understand-chat, understand-diff, understand-explain, understand-onboard, and understand-domain already follow the secure pattern: GRAPH_COMMIT=$(git
rev-parse --verify --end-of-options "${GRAPH_COMMIT_RAW}^{commit}" 2>/dev/null)).
- Fix: Update skills/understand/SKILL.md and hooks/auto-update-prompt.md to resolve the commit hash before executing git diff:
```bash
GRAPH_COMMIT=$(git rev-parse --verify --end-of-options "${LAST_COMMIT_HASH}^{commit}" 2>/dev/null)
if [ -n "$GRAPH_COMMIT" ]; then
git diff --name-only "$GRAPH_COMMIT" HEAD -- .
fi

### Minimal reproduction

_No response_

### Plugin version

2.9.0

### Platform / client

Claude Code (CLI)

### OS + Node version

macos 26.5.2

### Primary language of the analyzed project

_No response_

### Approximate file count of the analyzed project

_No response_

### Relevant logs

```shell

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions