Read-only network egress mapper for Claude / Cursor / Codex Agent Skill directories.
egremap scans a skill folder locally, extracts every URL, domain, IP address, and network call pattern, and builds a complete egress map that traces each host back to the exact file and line where it appears. It then compares discovered hosts against a declaration file (.network.example or SKILL.md frontmatter) and reports undeclared endpoints.
It never uploads your files, never makes network requests, and never executes code inside the scanned directory.
Status: open-source MVP for validation. Not a SaaS. Not a paid-demand claim.
Agent Skills (Claude Code, Cursor, Codex) are distributed as directories containing SKILL.md, scripts, and config files. These skills routinely contact external hosts via curl, urllib, SDK calls, and hardcoded URLs. Before installing or publishing a skill, you want to know:
- Every host the skill can contact -- not just the obvious ones in
curlcommands, but also SDK imports (from openai import OpenAIimpliesapi.openai.com), bare domain references in config files, and hardcoded IP addresses. - Whether any host can be overridden by an environment variable (SSRF / redirect risk).
- Whether the skill contacts hosts that are not declared in a
.network.exampleallowlist.
egremap answers all three in one pass.
- Python 3.9+
- No third-party runtime dependencies
git clone https://github.com/Jiangki/egremap.git
cd egremap
# Demo fixtures
python3 -m egremap scan fixtures/clean-skill # exit 0
python3 -m egremap scan fixtures/noisy-skill # exit 1 (undeclared hosts)
python3 -m egremap scan fixtures/hostile-skill # exit 1 (env override + hardcoded IP)
# Scan your own skill
python3 -m egremap scan /path/to/your-skill
python3 -m egremap scan /path/to/your-skill --format json
python3 -m egremap scan /path/to/your-skill --format markdown --output report.md
# List all unique hosts
python3 -m egremap list /path/to/your-skill
# Trace why a specific host was flagged
python3 -m egremap why /path/to/your-skill api.github.comOptional install as a console script:
pip install -e .
egremap scan /path/to/your-skill| Code | Meaning |
|---|---|
0 |
No error-level findings (warnings and info allowed) |
1 |
One or more error-level findings, or warnings when --fail-on warn |
2 |
Invalid path / operational error |
| ID | Severity | Check |
|---|---|---|
NET001 |
info | Egress inventory: every discovered host with file/line references |
NET002 |
warning | Network call code (curl, urllib, requests, fetch, git clone, ...) without a resolvable URL in the same file |
NET003 |
error | Host not declared in .network.example or SKILL.md frontmatter |
NET004 |
error | Host URL can be overridden by an environment variable (SSRF / redirect risk) |
NET005 |
warning | Hardcoded IP address or non-HTTPS egress |
NET006 |
info | API key read in a file that also makes network calls |
Create a .network.example file in the root of your skill directory:
# Declare every host this skill is allowed to contact.
api.github.com
codeload.github.com
Or declare them in SKILL.md frontmatter:
---
name: my-skill
description: Does something useful.
network:
allowed_hosts:
- api.github.com
- codeload.github.com
---egremap compares declared hosts against discovered hosts. Any host not in the declaration triggers NET003.
If no declaration exists at all, NET003 is downgraded to a warning (so the first run guides you to create one rather than flooding with errors).
| Extractor | What it finds |
|---|---|
| URL | Full http:// / https:// URLs in any text file |
| Bare host | Domain references in config/docs (.md, .yaml, .json, .example, ...) |
| IP address | IPv4 addresses (public and private) |
| Network call | curl, wget, urllib, requests, httpx, aiohttp, fetch(), git clone, ssh, nc |
| SDK import | from openai import, import anthropic, from google.generativeai import -- implies a fixed endpoint |
| Env override | HOST="${HOST:-https://...}" patterns where a host can be redirected |
| API key | os.getenv("XXX_API_KEY") in files that also make network calls |
egremap only lists directories, reads regular files, and inspects metadata. It does not:
- import or execute files from the scanned directory
- run shell commands from the skill
- follow symlinks into/out of the tree
- make network requests or verify host reachability
- write into the scanned directory
# .github/workflows/egress-check.yml
name: Egress audit
on: [pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: git clone https://github.com/Jiangki/egremap.git ../egremap
- run: python -m egremap scan ./my-skill --fail-on warn
working-directory: ${{ github.workspace }}
env:
PYTHONPATH: ../egremappython3 tests/test_egremap.py
# or
PYTHONPATH=. python3 -m unittest discover -s tests -vMIT - see LICENSE.
Extracted from the github-hot-tracker experiment pipeline (open-source-first idea -> pre-release MVP).