Skip to content

Back to the catalog

Symlinks Are Still Scary (And Yes, You Can Commit Them to Git)
snyk.ioarticle

Symlinks Are Still Scary (And Yes, You Can Commit Them to Git)

Snyk explains the decades-old symlink attack (CWE-61) and the underappreciated fact that Git will happily commit, push, and recreate symlinks (file mode 120000) from a cloned repo, letting an attacker ship a file like project_settings.json that's secretly a pointer to ~/.ssh/authorized_keys. It walks through Wiz Research's "GhostApproval" report, which found that six AI coding agents (Amazon Q Developer, Claude Code, Augment, Cursor, Google Antigravity, Windsurf) can be prompt-injected via README instructions into following such a symlink and writing attacker SSH keys or shell-config payloads before the user ever sees an accurate confirmation dialog (CWE-451, UI misrepresentation). It also recaps prior symlink-driven CVEs (tar npm package CVE-2021-32803, Leaky Vessels CVE-2024-21626, Git submodule CVE-2024-32002) and gives concrete mitigations: canonicalize-then-check-boundary atomically (e.g. openat2 with RESOLVE_BENEATH), show real resolved targets in approval dialogs, and audit repos with `find . -type l` or `git ls-files -s` before trusting them.

TL;DR Git happily commits and recreates symlinks, so a repo can ship a fake "config file" that's actually a pointer to ~/.ssh/authorized_keys — and Wiz's GhostApproval research shows Claude Code, Cursor, Windsurf, Amazon Q Developer and others can all be tricked via README prompt injection into writing to it before an honest confirmation dialog appears.
Document

What it is

A Snyk blog post (Randall Degges, July 9 2026) on symlink attacks delivered through Git repositories. Beyond the AI-assistant incident the summary describes, the page supplies the concrete Git internals, the platform boundary, and the detection tells an engineer needs to reason about their own exposure.

How it works

A symlink is a file whose entire contents are a path; the OS transparently redirects any open of the link to that target. Git stores symlinks with file mode 120000, and the blob content is nothing but the target path as plain text. So a file named e.g. project_settings.json can have blob contents of /home/rdegges/.ssh/authorized_keys. On clone, Git faithfully recreates the symlink on disk. Nothing has been exploited yet — the danger is the next tool (build script, editor, AI agent) that reads or writes through the checkout without resolving where the path actually goes, turning a clone into arbitrary file read/write and often RCE. The archive-tool variant (tar/zip/npm) extracts a symlink and writes through it to escape the target directory — CVE-2021-32803 in the tar npm package is the textbook case.

Preconditions / Affected

  • Linux and macOS primarily. On Windows, Git leaves symlinks as plain text files unless core.symlinks is enabled — so this "mostly bites Linux and macOS, which is to say most developer laptops and nearly all CI."
  • A tool that opens paths in a checkout without resolving them. Git's own checkout is not the weak point (see Caveats).

What to do

Inspect suspicious files before any tool touches them. ls -l reveals a symlink by the leading l and the -> in the listing; readlink <file> prints the target path the link points at rather than following it. GitHub renders symlinks correctly in its UI, so they are spottable in the web view if you know to look.

Caveats

  • Git was already partly hardened by the 2021-era CVEs: modern Git will not follow a symlink to write outside the working tree or into .git during its own operations. That protects only the checkout step — Git still legitimately creates the symlink as an inert file, and cannot control what reads it afterward.
  • Detection relies on someone actually looking; "nobody's auditing every file in every dependency they pull," which is the gap the attack exploits.
  • The fetched text is truncated mid-sentence in the mitigation discussion, so the post's full remediation guidance is not captured here.
flowchart TD
    A[Clone repo with malicious symlink] --> B{Tool resolves path<br/>before open?}
    B -->|Yes / ls -l, readlink| C[Symlink spotted — safe]
    B -->|No: build, editor, AI agent| D[Writes/reads through link]
    D --> E[File access outside repo → RCE]

Organisations named here

  • CWE-451
  • CWE-61
  • Leaky Vessels
  • Wiz Research
  • Zip Slip

CVEs named here

  • CVE-2021-32803
  • CVE-2024-21626
  • CVE-2024-32002

Technologies named here

  • Amazon Q Developer
  • Wiz Research / GhostApproval report
  • Claude Code
  • Snyk Research "Inside the Agentic Development Supply Chain"
  • Augment
  • Zip Slip
  • Cursor
  • find
  • Google Antigravity
  • git ls-files -s
  • Windsurf
  • readlink
  • git
  • ls -l
  • tar npm package
  • openat2 with RESOLVE_BENEATH / RESOLVE_NO_SYMLINKS
  • O_NOFOLLOW
  • Incus
  • GitHub
  • npm

Techniques named here

  • Symlink attack
  • Committing symlinks to Git repositories
  • Archive symlink extraction attack
  • Zip Slip / path traversal in archive extraction
  • /tmp race condition
  • Container escape via symlink and file-descriptor leak
  • Git submodule/recursive clone code execution
  • GhostApproval
  • Prompt Injection
  • UI misrepresentation