<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Harshit Sharma</title>
    <description>The latest articles on DEV Community by Harshit Sharma (@harshitethic).</description>
    <link>https://dev.to/harshitethic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4189797%2F2ef17831-8bbb-4cc4-b941-50d0a8b760cb.png</url>
      <title>DEV Community: Harshit Sharma</title>
      <link>https://dev.to/harshitethic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/harshitethic"/>
    <language>en</language>
    <item>
      <title>Repository hooks to inspect before trusting a GitHub project</title>
      <dc:creator>Harshit Sharma</dc:creator>
      <pubDate>Sun, 18 Oct 2026 03:59:03 +0000</pubDate>
      <link>https://dev.to/harshitethic/repository-hooks-to-inspect-before-trusting-a-github-project-28p4</link>
      <guid>https://dev.to/harshitethic/repository-hooks-to-inspect-before-trusting-a-github-project-28p4</guid>
      <description>&lt;p&gt;Opening a folder, installing dependencies, attaching a coding agent, or launching a devcontainer can activate configuration-defined commands. Here is a short checklist for finding the known entry points before you decide what to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the scope, not a security score
&lt;/h2&gt;

&lt;p&gt;Repository configuration can describe what a development tool &lt;em&gt;may&lt;/em&gt; run later. Seeing a command in a file is not proof that it executed, that the author is malicious, or that the project is compromised. Triggers depend on individual package-manager, editor, trust and agent settings.&lt;/p&gt;

&lt;p&gt;Review an unfamiliar checkout from a separate trusted terminal &lt;strong&gt;before&lt;/strong&gt; installing its packages, opening it as a trusted editor workspace, or starting a coding agent. Even cloning is not a sandbox: your local Git configuration and environment may affect Git operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Package-manager lifecycle scripts
&lt;/h2&gt;

&lt;p&gt;Look in &lt;code&gt;package.json&lt;/code&gt;, especially the &lt;code&gt;scripts&lt;/code&gt; keys &lt;code&gt;preinstall&lt;/code&gt;, &lt;code&gt;install&lt;/code&gt;, &lt;code&gt;postinstall&lt;/code&gt;, &lt;code&gt;prepare&lt;/code&gt; and &lt;code&gt;prepack&lt;/code&gt;. Some package-manager operations can invoke these automatically. A normal lifecycle command is not inherently suspicious; check the script and the programs it calls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"postinstall"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node scripts/verify-setup.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an &lt;strong&gt;inert illustration&lt;/strong&gt;. Do not execute it to inspect it. ClonePeek models these npm surfaces and follows one statically identifiable hop into literal local &lt;code&gt;.sh&lt;/code&gt; references, but it does not analyze arbitrary JavaScript imports or recursive script execution.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. VS Code automatic folder-open tasks
&lt;/h2&gt;

&lt;p&gt;Inspect &lt;code&gt;.vscode/tasks.json&lt;/code&gt; for tasks that declare &lt;code&gt;runOptions.runOn: folderOpen&lt;/code&gt;. Whether a task runs when the folder is opened depends on workspace trust and automatic-task settings. Read the command, task arguments and referenced files before accepting the workspace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tasks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example setup task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"echo review-me"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"runOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"runOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"folderOpen"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;echo&lt;/code&gt; value is deliberately harmless; this snippet exists to demonstrate the configuration shape, not to perform a setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Devcontainer lifecycle
&lt;/h2&gt;

&lt;p&gt;Review &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; for &lt;code&gt;initializeCommand&lt;/code&gt;, &lt;code&gt;onCreateCommand&lt;/code&gt;, &lt;code&gt;postCreateCommand&lt;/code&gt;, &lt;code&gt;postStartCommand&lt;/code&gt; and &lt;code&gt;postAttachCommand&lt;/code&gt;. Those correspond to different phases of creating, starting and attaching to a development environment. Devcontainer features can also introduce build-time setup. An isolated container is not a blanket guarantee of safety when it has mounts, credentials or network access.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Claude Code command hooks
&lt;/h2&gt;

&lt;p&gt;Look at project files such as &lt;code&gt;.claude/settings.json&lt;/code&gt; and &lt;code&gt;.claude/settings.local.json&lt;/code&gt;. Command hooks can be attached to events such as &lt;code&gt;SessionStart&lt;/code&gt; or &lt;code&gt;PostToolUse&lt;/code&gt;. Activation depends on the agent and its configuration. Treat instructions, tools and automatic commands from a new project as untrusted until reviewed.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Cursor workspace and agent hooks
&lt;/h2&gt;

&lt;p&gt;Look for &lt;code&gt;.cursor/hooks.json&lt;/code&gt;, including event definitions such as &lt;code&gt;workspaceOpen&lt;/code&gt; and &lt;code&gt;afterFileEdit&lt;/code&gt;. Read &lt;em&gt;what will be invoked, when, and by which process&lt;/em&gt;. A passive review tool should never trigger the hook merely to discover its output.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Local MCP process launch configuration
&lt;/h2&gt;

&lt;p&gt;Review the local MCP configuration your agent or editor may consume, particularly each &lt;code&gt;mcpServers&lt;/code&gt; entry with a &lt;code&gt;command&lt;/code&gt;, &lt;code&gt;args&lt;/code&gt;, environment variables and filesystem references. These are process-launch instructions, not necessarily running servers. They may take effect only when the client enables or approves them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run a passive review in a trusted terminal
&lt;/h2&gt;

&lt;p&gt;I maintain &lt;a href="https://github.com/harshitethic/clonepeek" rel="noopener noreferrer"&gt;ClonePeek&lt;/a&gt;, a small MIT-licensed Python CLI and GitHub Action for enumerating the modeled entry points above. The scan reads bounded configuration files and does &lt;strong&gt;not&lt;/strong&gt; run the target repository's scripts. Downloading/installing the scanner itself uses a network connection; the scan itself operates offline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvx &lt;span class="nt"&gt;--from&lt;/span&gt; git+https://github.com/harshitethic/clonepeek@v0.5.1 clonepeek /path/to/repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an inert demonstration, use the bundled &lt;a href="https://github.com/harshitethic/clonepeek/tree/main/examples/agent-hooks" rel="noopener noreferrer"&gt;agent-hooks fixture&lt;/a&gt;. Review the &lt;strong&gt;trigger&lt;/strong&gt; , source &lt;strong&gt;path and line&lt;/strong&gt; , example &lt;strong&gt;evidence&lt;/strong&gt; , and suggested review advice for each finding. None of the example commands needs to run.&lt;/p&gt;

&lt;p&gt;You can also start with this non-blocking PR workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Review execution hooks&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;harshitethic/clonepeek@v0.5.1&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
          &lt;span class="na"&gt;fail-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;none&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/harshitethic/clonepeek/blob/main/docs/GITHUB-ACTION.md" rel="noopener noreferrer"&gt;Action integration guide&lt;/a&gt; explains thresholds, baselines, JSON/SARIF and changed-file mode.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a clean result does &lt;em&gt;not&lt;/em&gt; mean
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No scanner can promise a safe repository.&lt;/strong&gt; ClonePeek deliberately omits dynamic references, many language/build execution paths and other unsupported tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Severity means review urgency.&lt;/strong&gt; Common, benign setup tasks can still receive high heuristic severity, while obfuscated or unsupported paths can be missed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Baseline does not equal approval.&lt;/strong&gt; A finding marked known is still an execution-capable surface; it merely matched your stored fingerprint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scan reports can contain sensitive content.&lt;/strong&gt; Redaction is best effort. Review and sanitize source excerpts before posting an artifact or CI comment publicly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Git operations deserve a boundary review too.&lt;/strong&gt; ClonePeek's &lt;a href="https://harshitethic.github.io/clonepeek/articles/git-fsmonitor-passive-scanning.html" rel="noopener noreferrer"&gt;Git fsmonitor case study&lt;/a&gt; documents a prior bug where a passive-looking diff invoked a configured helper. This was fixed with regression tests; it is not a sandbox guarantee.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Help improve the checklist
&lt;/h2&gt;

&lt;p&gt;Have a harmless repository hook that is missing or misclassified? A tiny inert reproduction and clear expected trigger help more than generic praise. The public &lt;a href="https://github.com/harshitethic/clonepeek/blob/main/docs/THREAT_MODEL.md" rel="noopener noreferrer"&gt;threat model&lt;/a&gt; lists blind spots, and the &lt;a href="https://github.com/harshitethic/clonepeek/blob/main/docs/EVALUATION.md" rel="noopener noreferrer"&gt;labeled synthetic evaluation&lt;/a&gt; is explicitly &lt;strong&gt;not&lt;/strong&gt; independent real-world accuracy evidence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/harshitethic/clonepeek/issues/14" rel="noopener noreferrer"&gt;Contribute an inert field test ↗&lt;/a&gt; &lt;a href="https://github.com/harshitethic/clonepeek/releases/tag/v0.5.1" rel="noopener noreferrer"&gt;Get the stable release ↗&lt;/a&gt; &lt;a href="https://harshitethic.github.io/clonepeek/" rel="noopener noreferrer"&gt;Explore ClonePeek ↗&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I maintain ClonePeek. This DEV cross-post was prepared with AI assistance from my original, publicly available technical guide and is not an independent endorsement. See the repository threat model for the exact scan boundaries.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>devtools</category>
      <category>opensource</category>
      <category>githubactions</category>
    </item>
    <item>
      <title>My read-only Python scanner accidentally ran a Git helper</title>
      <dc:creator>Harshit Sharma</dc:creator>
      <pubDate>Sat, 17 Oct 2026 04:21:42 +0000</pubDate>
      <link>https://dev.to/harshitethic/my-read-only-python-scanner-accidentally-ran-a-git-helper-2ni0</link>
      <guid>https://dev.to/harshitethic/my-read-only-python-scanner-accidentally-ran-a-git-helper-2ni0</guid>
      <description>&lt;p&gt;We were building a tool whose defining promise was simple: inspect unfamiliar repository configuration without executing its code. Then a test revealed that an ordinary-looking Git operation could launch a program defined by the repository itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small assumption with big consequences
&lt;/h2&gt;

&lt;p&gt;You're about to open a GitHub repository in your editor. You want to know which commands may run through package installation, trusted workspace tasks, devcontainer startup, MCP servers or an AI coding agent. A static auditor looks like a reasonable first line of review.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/harshitethic/clonepeek" rel="noopener noreferrer"&gt;ClonePeek&lt;/a&gt; was designed for that job. Its scanner traverses recognized configuration files using bounded reads and reports &lt;strong&gt;trigger → command → source location → suggested review&lt;/strong&gt; , without launching the project's npm scripts, shell hooks, or coding agents.&lt;/p&gt;

&lt;p&gt;There is a useful optional flag: &lt;code&gt;--changed-since&lt;/code&gt; filters findings to Git changes. Our first implementation called a local &lt;code&gt;git diff&lt;/code&gt; command. It felt harmless. Diffing files isn't building the repository, right?&lt;/p&gt;

&lt;p&gt;The catch is that &lt;strong&gt;Git's execution behavior can depend on checkout-local or inherited configuration, not just the arguments my code passes&lt;/strong&gt;. In particular, a local &lt;code&gt;core.fsmonitor&lt;/code&gt; setting can name a hook-like helper program. Depending on the command and Git version, Git may invoke that helper while refreshing file state. A subprocess invoked by the auditor was therefore enough to break our passive-scan invariant.&lt;/p&gt;

&lt;p&gt;One important boundary: a normal &lt;code&gt;git clone&lt;/code&gt; does &lt;strong&gt;not&lt;/strong&gt; transfer the remote repo's &lt;code&gt;.git/config&lt;/code&gt;. The issue is an existing checkout and its local configuration or inherited Git environment; don't confuse it with a malicious &lt;code&gt;package.json&lt;/code&gt; remotely rewriting Git config simply by being cloned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the regression observable
&lt;/h2&gt;

&lt;p&gt;To test this safely, we created a disposable local fixture with a deliberately inert helper that merely wrote a marker file. We did not use a real suspicious repository, download an executable payload, or depend on a network request.&lt;/p&gt;

&lt;p&gt;The test asked one specific question: &lt;strong&gt;can the audit complete without creating that marker?&lt;/strong&gt; Before the fix, the marker appeared. After the fix, it did not. Reproducing the violation as a filesystem side effect made it much harder for later refactors to accidentally reintroduce it.&lt;/p&gt;

&lt;p&gt;This is not a claim that every &lt;code&gt;git diff&lt;/code&gt; invocation on every operating system will execute an fsmonitor helper. It's a concrete example of why "I only ran Git" doesn't establish that no repo-defined execution occurred.&lt;/p&gt;

&lt;p&gt;The exact reproduction and safety constraints are in the &lt;a href="https://github.com/harshitethic/clonepeek/blob/main/docs/GIT-CONFIG-ISOLATION.md" rel="noopener noreferrer"&gt;Git configuration isolation notes&lt;/a&gt;; the patch and review trail are in &lt;a href="https://github.com/harshitethic/clonepeek/pull/5" rel="noopener noreferrer"&gt;PR #5&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The defense has to cover the helper process
&lt;/h2&gt;

&lt;p&gt;Python's read-only filesystem operations were not the issue. The boundary changed when the scanner delegated work to Git, a separate executable capable of honoring configuration, helpers and extensions. Fixing it required controlling &lt;em&gt;both&lt;/em&gt; process arguments and the environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Excerpted structure, not a standalone security sandbox
&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;git&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;core.fsmonitor=false&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;core.hooksPath=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;devnull&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diff.external=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;protocol.ext.allow=never&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-c&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;protocol.file.allow=never&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-C&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repo_root&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;diff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--no-ext-diff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--no-textconv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--name-only&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-z&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--diff-filter=ACMR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The scanner also strips inherited Git-specific variables and dangerous loader/Python environment overrides, disables system/global Git config for this invocation, rejects unexpected ref syntax, bounds subprocess runtime, and treats a failed diff as an error rather than silently reporting an empty result. These are &lt;strong&gt;defense-in-depth choices for an explicitly limited operation&lt;/strong&gt; ; they are not equivalent to process isolation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important limit:&lt;/strong&gt; This hardening is targeted to the Git invocation used by ClonePeek. Git and the host operating system have more behavior than one wrapper can model. Do not treat ClonePeek as a sandbox, a malware detector, or a reliable way to execute other tools against actively malicious content.&lt;/p&gt;

&lt;h2&gt;
  
  
  The next surprise was a script one file away
&lt;/h2&gt;

&lt;p&gt;Another coverage gap turned out to be less dramatic but equally useful. A &lt;code&gt;package.json&lt;/code&gt; file could contain a short lifecycle command such as &lt;code&gt;sh ./scripts/setup.sh&lt;/code&gt;. A surface-only scanner recognized the install hook, but the interesting command might live inside &lt;code&gt;scripts/setup.sh&lt;/code&gt;, outside the JSON.&lt;/p&gt;

&lt;p&gt;We added &lt;strong&gt;bounded, first-hop, read-only inspection&lt;/strong&gt; for statically identifiable local &lt;code&gt;.sh&lt;/code&gt; references. It checks that paths stay inside the repository, rejects symlink escapes and unsafe file types, and limits references, file sizes and lines read. It doesn't shell-expand arbitrary expressions or chase unbounded nested scripts.&lt;/p&gt;

&lt;p&gt;That sounds modest—and that's intentional. A scanner that executes the referenced script "to find out what it does" would solve one detection problem by discarding its own execution boundary. ClonePeek instead tells you what it can and can't see.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing a release from outside the repository
&lt;/h2&gt;

&lt;p&gt;Internal tests can miss assumptions about packaging. The v0.5.0 GitHub Action therefore has separate integration CI on Linux, macOS and Windows, plus an actual consumer workflow in another repository. That consumer workflow read two pinned, public configuration snapshots (Cursor hooks and VS Code folder-open tasks), checked their Git blob hashes, and asserted paths and classifications. No upstream hooks were run.&lt;/p&gt;

&lt;p&gt;These are narrow &lt;a href="https://github.com/harshitethic/clonepeek/blob/main/docs/CROSS-REPO-SMOKE.md" rel="noopener noreferrer"&gt;smoke tests&lt;/a&gt;, not independent outside-user adoption or an estimate of detection accuracy. The &lt;a href="https://github.com/harshitethic/clonepeek/blob/main/docs/EVALUATION.md" rel="noopener noreferrer"&gt;hand-authored synthetic evaluation&lt;/a&gt; deliberately includes false positives and false negatives; it is not representative of internet repositories.&lt;/p&gt;

&lt;h2&gt;
  
  
  A checklist for tools that inspect untrusted projects
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Map all execution paths, including your own helper commands.&lt;/strong&gt; A safe-looking wrapper doesn't make delegated subprocesses inert.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write regression tests around side effects, not only output strings.&lt;/strong&gt; A marker file can reveal unexpected execution even when the scanner report looks correct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Constrain filesystem reads and traversal.&lt;/strong&gt; Symlinks, special files, large files and path escapes matter even when you never execute a script.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate supported detection from safety claims.&lt;/strong&gt; A command hook is a review prompt, not proof that an author is malicious.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make failure visible.&lt;/strong&gt; Parse errors and unsupported references should not silently become "nothing found."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're auditing a repository you don't trust, the safest workflow begins before installing its dependencies or marking it trusted in an IDE. The &lt;a href="https://github.com/harshitethic/clonepeek/blob/main/docs/BEFORE-YOU-TRUST-A-REPO.md" rel="noopener noreferrer"&gt;five-minute pre-trust audit guide&lt;/a&gt; covers practical next steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it. Critique it. Improve it.
&lt;/h2&gt;

&lt;p&gt;ClonePeek v0.5.1 is MIT licensed, has no runtime Python dependencies, and exposes its threat model publicly. We're looking for real, inert examples of execution hooks it misses or overclassifies—not drive-by stars or artificial PRs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;uvx &lt;span class="nt"&gt;--from&lt;/span&gt; git+https://github.com/harshitethic/clonepeek@v0.5.1 &lt;span class="se"&gt;\&lt;/span&gt;
  clonepeek /path/to/repository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/harshitethic/clonepeek" rel="noopener noreferrer"&gt;Browse source ↗&lt;/a&gt; &lt;a href="https://github.com/harshitethic/clonepeek/issues/14" rel="noopener noreferrer"&gt;Contribute a real improvement ↗&lt;/a&gt; &lt;a href="https://harshitethic.github.io/clonepeek/" rel="noopener noreferrer"&gt;Live demo ↗&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: I maintain ClonePeek. This case study was prepared with AI writing assistance and reviewed against the source, tests, and public docs. Maintainer-run tests are not independent security evaluation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>security</category>
      <category>opensource</category>
      <category>githubactions</category>
    </item>
  </channel>
</rss>
