[BUG] security-guidance truncates diffs at embedded "diff --git " source text
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
Research direction
Start by reading plugins/security-guidance/hooks/gitutil.py and the parse_diff_into_files reproduction in the issue. Check how it identifies file headers and look for existing tests covering diff parsing. Done means added lines containing diff --git remain in the parsed file diff, while actual file headers still separate files; verify both staged and committed diffs.
Written by the indexing model from the issue text.
Description
Summary
parse_diff_into_files splits the entire diff on every occurrence of diff --git , including occurrences inside source lines. An ordinary string literal can therefore truncate the diff forwarded to security review.
Source audit and local reproduction at commit 3deb873687379f0c199a69fdaccc65f0865f7a29, Windows / Python 3.13. No Claude CLI/model version was exercised.
Reproduce
Run the following Python from the repository root. It creates a temporary Git repository; the generated source files are never executed.
import subprocess, sys, tempfile
from pathlib import Path
sys.dont_write_bytecode = True
sys.path.insert(0, str(Path.cwd() / "plugins/security-guidance/hooks"))
from gitutil import parse_diff_into_files
with tempfile.TemporaryDirectory() as tmp:
repo = Path(tmp)
def git(*args):
return subprocess.check_output(
["git", "-c", "core.hooksPath=/dev/null", *args],
cwd=repo).decode("utf-8")
git("init", "-q")
git("-c", "user.name=Audit", "-c", "[email protected]",
"commit", "--allow-empty", "-qm", "baseline")
(repo / "embedded.py").write_text(
'prefix = "diff --git "\nprint("AFTER_MARKER")\n', encoding="utf-8")
(repo / "normal.py").write_text(
'print("CONTROL_MARKER")\n', encoding="utf-8")
git("add", ".")
diff = git("diff", "--cached", "--no-color", "--no-ext-diff", "HEAD")
parsed = dict(parse_diff_into_files(diff))
print(repr(parsed["embedded.py"]))
assert "AFTER_MARKER" in diff
assert "AFTER_MARKER" not in parsed["embedded.py"] # defect
assert "CONTROL_MARKER" in parsed["normal.py"]
git("-c", "user.name=Audit", "-c", "[email protected]",
"commit", "-qm", "fixture")
committed = dict(parse_diff_into_files(
git("show", "-p", "--no-color", "--no-ext-diff", "HEAD", "--")))
assert "AFTER_MARKER" not in committed["embedded.py"]
Actual versus expected
Actual parsed embedded.py diff:
@@ -0,0 +1,2 @@
+prefix = "
The remainder of the string line and the following print("AFTER_MARKER") addition disappear. The subsequent real normal.py diff remains intact. Expected: both complete added lines survive parsing; only actual file-header lines delimit files.
Cause and security-review impact
gitutil.py uses diff_output.split("diff --git ") without restricting the delimiter to actual header lines. The single-shot reviewer builds its input from the parsed diff strings, so the omitted tail cannot be reviewed through that input. A contributor could intentionally place this marker before a change.
This is a demonstrated parser/input-coverage defect, not prompt injection, an end-to-end model false-negative result, RCE, or sandbox escape. The agentic reviewer still receives the file path and can read the complete file, so a universal agentic-review bypass is not established.
Duplicate check and related report
Targeted public issue/PR searches for parse_diff_into_files, embedded diff markers, and security-guidance diff parsing found no matching report. PR #76274 concerns downstream path normalization and does not change this split operation. Separate quoted-header defect: #101547.
- Dominant language
- TypeScript
- Stars
- 151k
- Forks
- 26.4k
- Avg merge
- 19h 45m
- Merged PRs (30d)
- 32
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- No pull request template
- No contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from anthropics/claude-code
-
area:tui bug has repro platform:macos
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
anthropics/claude-code#101933 ·
Maintainers usually reply within 1 day
-
area:cowork area:desktop documentation enhancement platform:macos
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
anthropics/claude-code#101720 ·
Maintainers usually reply within 1 day
-
area:tui enhancement platform:macos
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
anthropics/claude-code#101490 ·
Maintainers usually reply within 1 day
-
area:ide bug platform:vscode platform:windows
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
anthropics/claude-code#101482 ·
Maintainers usually reply within 1 day
-
area:plugins documentation enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
anthropics/claude-code#101451 ·
Maintainers usually reply within 1 day
All issues in anthropics/claude-code
Similar issues
-
Add: VIVE TVOpenapproved check:passed streams:add
Difficulty 1/5 Under an hour Newbie friendliness 72/100
iptv-org/iptv#55293 · 1 comment ·
Maintainers usually reply within 1 day
-
bug needs-triage
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
Fission-AI/OpenSpec#2084 ·
Maintainers usually reply within 2 days
-
Contrib indemnité de départ à la retraite : faire le pont avec le simulateur sur la page génériqueOpenP1
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
SocialGouv/code-du-travail-numerique#7561 ·
Maintainers usually reply within 1 day
-
beginner bug
Difficulty 1/5 Under an hour Newbie friendliness 88/100
hiero-ledger/hiero-sdk-js#4517 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
kubernetes-sigs/headlamp#7950 ·
Maintainers usually reply within 3 days