Global Storage Forum

Global Storage Forum

Connect, collaborate, and stay informed with insights from across Storage

 View Only

How to Run GitHub Projects Safely — and Avoid Getting Hacked

By Randhir Singh posted 6 hours ago

  

The Problem: “It’s Just a GitHub Repo… What Could Go Wrong?”

As developers, we live on GitHub.
It’s second nature to clone a new repo, install dependencies, and run it — especially if it looks legit, comes from a job interviewer, or promises a cool new framework demo.

But what if that repo isn’t what it seems?

In a blog post by David Dodda, he shared how a fake interview coding task almost led him to execute malware on his laptop.
The attacker simply sent him a “GitHub repo” and asked him to run it quickly during the interview.
No zero-day exploits. No kernel hacking. Just developer trust — exploited.

This isn’t rare. Modern attacks increasingly target developers themselves, because developer machines often hold API keys, SSH credentials, cloud configs, and internal tokens.

What Can Go Wrong When You “Just Run It”

Let’s break it down:

  • Malicious scripts can steal ~/.ssh/id_rsa, .aws/credentials, or browser cookies.

  • npm/pip/postinstall hooks can silently execute arbitrary shell commands.

  • Dockerfiles and Makefiles can run curl | bash patterns on your host.

  • Container escapes or volume mounts can expose your real home directory.

  • Credential managers (like gh auth, aws configure, gcloud) can be hijacked.

In short: “git clone && run” is the new double-clicking random .exe.

The Safer Way: Use a Dev Container Sandbox

The solution isn’t to stop exploring open source — it’s to do it safely.

A dev container (like those supported by VS Code or Podman/Docker) gives you an isolated environment that mirrors a developer machine but with strong boundaries:

  • Separate filesystem

  • Non-root user

  • Optional network isolation

  • Disposable (destroy on exit)

  • No host credentials by default

So even if the code is malicious, it’s trapped inside the sandbox.

Our Solution: The safe-dev-runner

To make this safe workflow easy, I created safe-dev-runner — a lightweight way to clone and run any GitHub project inside a locked-down dev container.

Step 1 – Clone the Runner

git clone https://github.com/Randhir123/safe-dev-runner.git
cd safe-dev-runner

Step 2 – Build the image

./dev.sh --build

This pulls mcr.microsoft.com/devcontainers/base:ubuntu, installs packages, and tags the result as dev:latest. Re-run whenever you modify dev.dockerfile.

Step 3 - Launching the Dev Shell

From any project directory:

/path/to/dev.sh

The script mounts the current directory and caches into the container. You drop into /bin/bash as user vscode (UID 1000). Install dependencies and run commands there—your working tree stays on the host.

Example Workflow

Let's dry run this solution. We want to safely run examples in repository - https://github.com/a2aproject/a2a-samples.git. This repository contains code samples and demos which use the Agent2Agent (A2A) Protocol.

Clone and Work on a GitHub Project

% git clone https://github.com/a2aproject/a2a-samples.git
Cloning into 'a2a-samples'...
remote: Enumerating objects: 5055, done.
remote: Counting objects: 100% (131/131), done.
remote: Compressing objects: 100% (56/56), done.
remote: Total 5055 (delta 90), reused 75 (delta 75), pack-reused 4924 (from 2)
Receiving objects: 100% (5055/5055), 27.77 MiB | 15.23 MiB/s, done.
Resolving deltas: 100% (2804/2804), done.
% cd a2a-samples 
% ~/pers/dev_containers/dev.sh

This launches the dev container and mounts the folder inside it. Once inside, navigate to the sample that you want to run. Start the server inside the dev container.

vscode ➜ /Users/randhirkumarsingh/pers/a2a-samples (main) $ cd samples/python/agents/
vscode ➜ .../a2a-samples/samples/python/agents (main) $ ls
README.md                  a2a_telemetry              adk_facts                  analytics                         beeai-chat            crewai           github-agent         langgraph              mindsdb               travel_planner_agent
a2a-mcp-without-framework  adk_cloud_run              ag2                        any_agent_adversarial_multiagent  birthday_planner_adk  dice_agent_grpc  headless_agent_auth  llama_index_file_chat  number_guessing_game  veo_video_gen
a2a_mcp                    adk_expense_reimbursement  airbnb_planner_multiagent  azureaifoundry_sdk                content_planner       dice_agent_rest  helloworld           marvin                 semantickernel
vscode ➜ .../a2a-samples/samples/python/agents (main) $ cd helloworld/
vscode ➜ .../samples/python/agents/helloworld (main) $ ls
Containerfile  README.md  __init__.py  __main__.py  agent_executor.py  pyproject.toml  test_client.py  uv.lock
vscode ➜ .../samples/python/agents/helloworld (main) $ uv run .
Using CPython 3.12.3 interpreter at: /usr/bin/python3
Creating virtual environment at: .venv
      Built helloworld @ file:///Users/randhirkumarsingh/pers/a2a-samples/samples/python/agents/helloworld
░░░░░░░░░░░░░░░░░░░░ [0/55] Installing wheels...                                                                                                                                                                                                     warning: Failed to hardlink files; falling back to full copy. This may lead to degraded performance.
         If the cache and target directories are on different filesystems, hardlinking may not be supported.
         If this is intentional, set `export UV_LINK_MODE=copy` or use `--link-mode=copy` to suppress this warning.
Installed 55 packages in 1.38s
INFO:     Started server process [217]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:9999 (Press CTRL+C to quit)

To run the client, ssh into the same container and start client.

% podman container ls
CONTAINER ID  IMAGE                 COMMAND     CREATED        STATUS        PORTS       NAMES
09d03112ed08  localhost/dev:latest              7 minutes ago  Up 7 minutes              great_hellman
% podman exec -it 09d03112ed08 /bin/bash
vscode ➜ /Users/randhirkumarsingh/pers/a2a-samples $ ls
CODE_OF_CONDUCT.md  CONTRIBUTING.md  LICENSE  README.md  SECURITY.md  demo  extensions  format.sh  notebooks  pyproject.toml  requirements-dev.txt  samples
vscode ➜ /Users/randhirkumarsingh/pers/a2a-samples (main) $ cd samples/python/agents/helloworld/
vscode ➜ .../samples/python/agents/helloworld (main) $ uv run test_client.py
INFO:__main__:Attempting to fetch public agent card from: http://localhost:9999/.well-known/agent-card.json
INFO:httpx:HTTP Request: GET http://localhost:9999/.well-known/agent-card.json "HTTP/1.1 200 OK"
INFO:a2a.client.card_resolver:Successfully fetched agent card data from http://localhost:9999/.well-known/agent-card.json: {'capabilities': {'streaming': True}, 'defaultInputModes': ['text'], 'defaultOutputModes': ['text'], 'description': 'Just a hello world agent', 'name': 'Hello World Agent', 'preferredTransport': 'JSONRPC', 'protocolVersion': '0.3.0', 'skills': [{'description': 'just returns hello world', 'examples': ['hi', 'hello world'], 'id': 'hello_world', 'name': 'Returns hello world', 'tags': ['hello world']}], 'supportsAuthenticatedExtendedCard': True, 'url': 'http://localhost:9999/', 'version': '1.0.0'}
INFO:__main__:Successfully fetched public agent card:
INFO:__main__:{
  "capabilities": {
    "streaming": true
  },
  "defaultInputModes": [
    "text"
  ],
  "defaultOutputModes": [
    "text"
  ],
  "description": "Just a hello world agent",
  "name": "Hello World Agent",
  "preferredTransport": "JSONRPC",
  "protocolVersion": "0.3.0",
  "skills": [
    {
      "description": "just returns hello world",
      "examples": [
        "hi",
        "hello world"
      ],
      "id": "hello_world",
      "name": "Returns hello world",
      "tags": [
        "hello world"
      ]
    }
  ],
  "supportsAuthenticatedExtendedCard": true,
  "url": "http://localhost:9999/",
  "version": "1.0.0"
}
INFO:__main__:
Using PUBLIC agent card for client initialization (default).
INFO:__main__:
Public card supports authenticated extended card. Attempting to fetch from: http://localhost:9999/agent/authenticatedExtendedCard
INFO:httpx:HTTP Request: GET http://localhost:9999/agent/authenticatedExtendedCard "HTTP/1.1 200 OK"
INFO:a2a.client.card_resolver:Successfully fetched agent card data from http://localhost:9999/agent/authenticatedExtendedCard: {'capabilities': {'streaming': True}, 'defaultInputModes': ['text'], 'defaultOutputModes': ['text'], 'description': 'The full-featured hello world agent for authenticated users.', 'name': 'Hello World Agent - Extended Edition', 'preferredTransport': 'JSONRPC', 'protocolVersion': '0.3.0', 'skills': [{'description': 'just returns hello world', 'examples': ['hi', 'hello world'], 'id': 'hello_world', 'name': 'Returns hello world', 'tags': ['hello world']}, {'description': 'A more enthusiastic greeting, only for authenticated users.', 'examples': ['super hi', 'give me a super hello'], 'id': 'super_hello_world', 'name': 'Returns a SUPER Hello World', 'tags': ['hello world', 'super', 'extended']}], 'supportsAuthenticatedExtendedCard': True, 'url': 'http://localhost:9999/', 'version': '1.0.1'}
INFO:__main__:Successfully fetched authenticated extended agent card:
INFO:__main__:{
  "capabilities": {
    "streaming": true
  },
  "defaultInputModes": [
    "text"
  ],
  "defaultOutputModes": [
    "text"
  ],
  "description": "The full-featured hello world agent for authenticated users.",
  "name": "Hello World Agent - Extended Edition",
  "preferredTransport": "JSONRPC",
  "protocolVersion": "0.3.0",
  "skills": [
    {
      "description": "just returns hello world",
      "examples": [
        "hi",
        "hello world"
      ],
      "id": "hello_world",
      "name": "Returns hello world",
      "tags": [
        "hello world"
      ]
    },
    {
      "description": "A more enthusiastic greeting, only for authenticated users.",
      "examples": [
        "super hi",
        "give me a super hello"
      ],
      "id": "super_hello_world",
      "name": "Returns a SUPER Hello World",
      "tags": [
        "hello world",
        "super",
        "extended"
      ]
    }
  ],
  "supportsAuthenticatedExtendedCard": true,
  "url": "http://localhost:9999/",
  "version": "1.0.1"
}
INFO:__main__:
Using AUTHENTICATED EXTENDED agent card for client initialization.
/Users/randhirkumarsingh/pers/a2a-samples/samples/python/agents/helloworld/test_client.py:105: DeprecationWarning: A2AClient is deprecated and will be removed in a future version. Use ClientFactory to create a client with a JSON-RPC transport.
  client = A2AClient(
INFO:__main__:A2AClient initialized.
INFO:httpx:HTTP Request: POST http://localhost:9999/ "HTTP/1.1 200 OK"
{'id': '1cf9eb0d-acbe-42b3-8dc1-221d2313afba', 'jsonrpc': '2.0', 'result': {'kind': 'message', 'messageId': '3688180e-c299-43bf-9fd5-f537abcffbd0', 'parts': [{'kind': 'text', 'text': 'Hello World'}], 'role': 'agent'}}
INFO:httpx:HTTP Request: POST http://localhost:9999/ "HTTP/1.1 200 OK"
{'id': 'c0df8bf9-c6f6-4a97-8e3e-d31d77d07616', 'jsonrpc': '2.0', 'result': {'kind': 'message', 'messageId': 'ced9cea4-0fde-42b9-a1ee-b718a06f1524', 'parts': [{'kind': 'text', 'text': 'Hello World'}], 'role': 'agent'}}
vscode ➜ .../samples/python/agents/helloworld (main) $ 

Because both processes live in the same container, no extra port publishing is required. We have demonstrated how to run a project from GitHub safely inside a dev container.

Conclusion

Running open-source code safely is now a developer security skill.
The incident that was described could happen to anyone — but it’s preventable with a little discipline and the right tooling.

Use containers as your armor, not your afterthought.
And if you want a simple, reusable setup — grab safe-dev-runner and start exploring securely today.

0 comments
20 views

Permalink