skillscan-trace 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. skillscan_trace-0.1.0/.dockerignore +17 -0
  2. skillscan_trace-0.1.0/.github/workflows/ci.yml +46 -0
  3. skillscan_trace-0.1.0/.github/workflows/codeql.yml +29 -0
  4. skillscan_trace-0.1.0/.github/workflows/release-pypi.yml +51 -0
  5. skillscan_trace-0.1.0/.gitignore +30 -0
  6. skillscan_trace-0.1.0/CONTRIBUTING.md +71 -0
  7. skillscan_trace-0.1.0/Dockerfile +64 -0
  8. skillscan_trace-0.1.0/PKG-INFO +200 -0
  9. skillscan_trace-0.1.0/PRIVACY.md +95 -0
  10. skillscan_trace-0.1.0/README.md +162 -0
  11. skillscan_trace-0.1.0/ROADMAP.md +80 -0
  12. skillscan_trace-0.1.0/docker-compose.yml +45 -0
  13. skillscan_trace-0.1.0/pyproject.toml +67 -0
  14. skillscan_trace-0.1.0/skillscan-trace.example.yaml +76 -0
  15. skillscan_trace-0.1.0/skillscan_trace/__init__.py +7 -0
  16. skillscan_trace-0.1.0/skillscan_trace/canary/__init__.py +14 -0
  17. skillscan_trace-0.1.0/skillscan_trace/canary/bash_ast.py +383 -0
  18. skillscan_trace-0.1.0/skillscan_trace/canary/detectors.py +712 -0
  19. skillscan_trace-0.1.0/skillscan_trace/canary/server.py +1187 -0
  20. skillscan_trace-0.1.0/skillscan_trace/cli.py +721 -0
  21. skillscan_trace-0.1.0/skillscan_trace/config.py +209 -0
  22. skillscan_trace-0.1.0/skillscan_trace/formatters.py +268 -0
  23. skillscan_trace-0.1.0/skillscan_trace/harness.py +314 -0
  24. skillscan_trace-0.1.0/skillscan_trace/input_gen.py +152 -0
  25. skillscan_trace-0.1.0/skillscan_trace/judge/__init__.py +17 -0
  26. skillscan_trace-0.1.0/skillscan_trace/judge/judges.py +290 -0
  27. skillscan_trace-0.1.0/skillscan_trace/judge/models.py +90 -0
  28. skillscan_trace-0.1.0/skillscan_trace/judge/orchestrator.py +160 -0
  29. skillscan_trace-0.1.0/skillscan_trace/judge/prompt.py +159 -0
  30. skillscan_trace-0.1.0/skillscan_trace/models.py +153 -0
  31. skillscan_trace-0.1.0/skillscan_trace/resolver.py +265 -0
  32. skillscan_trace-0.1.0/skillscan_trace/serve.py +337 -0
  33. skillscan_trace-0.1.0/tests/__init__.py +1 -0
  34. skillscan_trace-0.1.0/tests/test_canary.py +722 -0
  35. skillscan_trace-0.1.0/tests/test_phase2.py +259 -0
  36. skillscan_trace-0.1.0/tests/test_phase3.py +383 -0
  37. skillscan_trace-0.1.0/tests/test_phase4.py +291 -0
  38. skillscan_trace-0.1.0/tests/test_phase5.py +380 -0
@@ -0,0 +1,17 @@
1
+ .git
2
+ .github
3
+ __pycache__
4
+ *.pyc
5
+ *.pyo
6
+ .pytest_cache
7
+ .mypy_cache
8
+ .ruff_cache
9
+ dist/
10
+ build/
11
+ *.egg-info/
12
+ trace-output/
13
+ trace-cache/
14
+ .env
15
+ *.env
16
+ tests/
17
+ docs/
@@ -0,0 +1,46 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: Lint, type-check & test
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ python-version: ["3.11", "3.12"]
16
+
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python ${{ matrix.python-version }}
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install dependencies
26
+ run: |
27
+ python -m pip install --upgrade pip
28
+ pip install -e ".[dev]"
29
+
30
+ - name: Format check (ruff)
31
+ if: matrix.python-version == '3.11'
32
+ run: ruff format --check .
33
+
34
+ - name: Lint (ruff)
35
+ if: matrix.python-version == '3.11'
36
+ run: ruff check .
37
+
38
+ - name: Type-check (mypy)
39
+ if: matrix.python-version == '3.11'
40
+ run: mypy skillscan_trace --ignore-missing-imports
41
+
42
+ - name: Run tests
43
+ run: pytest tests/ -q --tb=short
44
+ env:
45
+ # Tests use mock providers — no real API key needed
46
+ OPENAI_API_KEY: "sk-test-placeholder"
@@ -0,0 +1,29 @@
1
+ name: CodeQL
2
+ on:
3
+ push:
4
+ pull_request:
5
+ schedule:
6
+ - cron: '21 4 * * 1'
7
+ jobs:
8
+ analyze:
9
+ name: Analyze (python)
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ actions: read
13
+ contents: read
14
+ security-events: write
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ language: [python]
19
+ steps:
20
+ - name: Checkout repository
21
+ uses: actions/checkout@v4
22
+ - name: Initialize CodeQL
23
+ uses: github/codeql-action/init@v3
24
+ with:
25
+ languages: ${{ matrix.language }}
26
+ - name: Autobuild
27
+ uses: github/codeql-action/autobuild@v3
28
+ - name: Perform CodeQL Analysis
29
+ uses: github/codeql-action/analyze@v3
@@ -0,0 +1,51 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ build:
9
+ name: Build distribution
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+
14
+ - name: Set up Python
15
+ uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.11"
18
+
19
+ - name: Install build tools
20
+ run: |
21
+ python -m pip install --upgrade pip
22
+ pip install build
23
+
24
+ - name: Build package
25
+ run: python -m build
26
+
27
+ - name: Upload distribution artifacts
28
+ uses: actions/upload-artifact@v4
29
+ with:
30
+ name: dist
31
+ path: dist/
32
+
33
+ publish:
34
+ name: Publish to PyPI
35
+ needs: build
36
+ runs-on: ubuntu-latest
37
+ environment:
38
+ name: pypi
39
+ url: https://pypi.org/project/skillscan-trace/
40
+ permissions:
41
+ id-token: write # required for OIDC trusted publisher
42
+
43
+ steps:
44
+ - name: Download distribution artifacts
45
+ uses: actions/download-artifact@v4
46
+ with:
47
+ name: dist
48
+ path: dist/
49
+
50
+ - name: Publish to PyPI
51
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,30 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ .env
9
+
10
+ # Trace outputs
11
+ traces/
12
+ *.trace.json
13
+
14
+ # Canary state (never commit)
15
+ .canary_*/
16
+ .domain_state.json
17
+
18
+ # IDE
19
+ .vscode/
20
+ .idea/
21
+ *.swp
22
+
23
+ # OS
24
+ .DS_Store
25
+ Thumbs.db
26
+
27
+ # Test artifacts
28
+ .pytest_cache/
29
+ .coverage
30
+ htmlcov/
@@ -0,0 +1,71 @@
1
+ # Contributing to skillscan-trace
2
+
3
+ ## Context
4
+
5
+ skillscan-trace is the behavioral execution engine in the SkillScan family. It is a sibling project to [skillscan-security](https://github.com/kurtpayne/skillscan-security), which contains the static analyzer, ML classifier, and skill corpus.
6
+
7
+ If you are picking up this project for the first time, read these documents in order:
8
+
9
+ 1. [`README.md`](./README.md) — what the tool does and why
10
+ 2. [`SPEC.md`](./SPEC.md) — the complete behavioral specification (authoritative)
11
+ 3. [`ARCHITECTURE.md`](./ARCHITECTURE.md) — system design and component overview
12
+ 4. [`IMPLEMENTATION_PLAN.md`](./IMPLEMENTATION_PLAN.md) — ordered build plan with acceptance criteria
13
+ 5. [`skillscan-security/docs/TRACE_RESEARCH.md`](https://github.com/kurtpayne/skillscan-security/blob/main/docs/TRACE_RESEARCH.md) — research notes on prior art, canary taxonomy, and domain allowlist design
14
+
15
+ ## Repository relationship
16
+
17
+ The two repos share artifacts. When working on skillscan-trace, you may need to reference or update:
18
+
19
+ | Artifact | Location | Notes |
20
+ |---|---|---|
21
+ | Canary taxonomy | `skillscan-security/docs/TRACE_RESEARCH.md` | Source of truth for what to detect |
22
+ | Domain allowlist | `skillscan-security/trace/domains/verified.yml` | Bundled into skillscan-trace at build time |
23
+ | Finding ID namespace | `skillscan-security/src/skillscan/rules/` | Finding IDs must not conflict |
24
+ | Skill corpus | `skillscan-security/corpus/` | Used for integration tests and batch tracing |
25
+
26
+ ## Development setup
27
+
28
+ ```bash
29
+ git clone https://github.com/kurtpayne/skillscan-trace
30
+ cd skillscan-trace
31
+ python3 -m venv .venv && source .venv/bin/activate
32
+ pip install -e ".[dev]"
33
+
34
+ # Verify Ollama is running
35
+ ollama serve &
36
+ ollama pull qwen2.5:7b
37
+
38
+ # Run tests
39
+ pytest
40
+ ```
41
+
42
+ ## Implementation guidance
43
+
44
+ The `IMPLEMENTATION_PLAN.md` defines 10 milestones in dependency order. Start with Milestone 1 (instrumented MCP server) — it is the novel component with no prior art and everything else depends on it.
45
+
46
+ The MCP server should be testable standalone before the agent harness exists. Write a simple test client that sends tool calls directly to the server and verifies the interceptor behavior. This avoids needing a running model for unit tests.
47
+
48
+ The agent harness uses the OpenAI-compatible API that Ollama exposes at `http://localhost:11434/v1`. The same harness code works with real OpenAI/Anthropic models by changing the `base_url`. Do not write model-specific integration code.
49
+
50
+ ## Testing
51
+
52
+ Every interceptor must have unit tests. The integration test suite runs known-malicious and known-benign skills through the full pipeline. The skillscan-security corpus provides the test cases — clone it alongside this repo and set `SKILLSCAN_CORPUS_PATH` to point at it.
53
+
54
+ ```bash
55
+ export SKILLSCAN_CORPUS_PATH=../skillscan-security/corpus
56
+ pytest tests/integration/
57
+ ```
58
+
59
+ ## Design constraints
60
+
61
+ **No GPU required.** The default path must work on a laptop with 8GB RAM and no GPU. Do not add GPU-only dependencies to the core package.
62
+
63
+ **No API key required by default.** Ollama is the zero-friction path. API model support is a configuration option, not the default.
64
+
65
+ **Low compliance model.** The default model (`qwen2.5:7b`) is chosen for its low refusal rate, not its safety properties. This is intentional — see SPEC.md Section 4.1 for the rationale.
66
+
67
+ **Structured output first.** Every trace produces a machine-readable JSON report. Human-readable text is a formatting layer on top. Do not design the data model around the text output.
68
+
69
+ ## Versioning
70
+
71
+ skillscan-trace follows semantic versioning. The v1.0 milestone is defined by the acceptance criteria in `IMPLEMENTATION_PLAN.md`. Breaking changes to the trace report schema require a major version bump.
@@ -0,0 +1,64 @@
1
+ # skillscan-trace Docker image
2
+ #
3
+ # Supports two modes:
4
+ #
5
+ # Single trace (default):
6
+ # docker run --rm \
7
+ # -e OPENAI_API_KEY=$OPENAI_API_KEY \
8
+ # -v $(pwd)/my-skill.md:/skill.md:ro \
9
+ # skillscan/trace run /skill.md
10
+ #
11
+ # Self-hosted server:
12
+ # docker run -p 8080:8080 \
13
+ # skillscan/trace serve
14
+ #
15
+ # OpenRouter:
16
+ # docker run --rm \
17
+ # -e OPENROUTER_API_KEY=$OPENROUTER_API_KEY \
18
+ # -v $(pwd)/my-skill.md:/skill.md:ro \
19
+ # skillscan/trace run /skill.md --provider openrouter
20
+ #
21
+ # Ollama (fully local, no API key):
22
+ # docker run --rm \
23
+ # --network host \
24
+ # -v $(pwd)/my-skill.md:/skill.md:ro \
25
+ # skillscan/trace run /skill.md --provider ollama
26
+
27
+ FROM python:3.11-slim
28
+
29
+ # Security: run as non-root
30
+ RUN groupadd --gid 1001 skillscan && \
31
+ useradd --uid 1001 --gid skillscan --shell /bin/bash --create-home skillscan
32
+
33
+ WORKDIR /app
34
+
35
+ # Install system dependencies
36
+ RUN apt-get update && \
37
+ apt-get install -y --no-install-recommends \
38
+ git \
39
+ curl \
40
+ && rm -rf /var/lib/apt/lists/*
41
+
42
+ # Copy project files
43
+ COPY pyproject.toml README.md ./
44
+ COPY skillscan_trace/ ./skillscan_trace/
45
+
46
+ # Install with serve extras
47
+ RUN pip install --no-cache-dir ".[serve]"
48
+
49
+ # Create directories with correct ownership
50
+ RUN mkdir -p /trace-output /trace-cache && \
51
+ chown -R skillscan:skillscan /app /trace-output /trace-cache
52
+
53
+ USER skillscan
54
+
55
+ # Default output and cache directories
56
+ VOLUME ["/trace-output", "/trace-cache"]
57
+
58
+ # Health check for serve mode
59
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
60
+ CMD curl -f http://localhost:8080/v1/health || exit 1
61
+
62
+ # Default: show help. Override with `run /skill.md` or `serve`
63
+ ENTRYPOINT ["skillscan-trace"]
64
+ CMD ["--help"]
@@ -0,0 +1,200 @@
1
+ Metadata-Version: 2.4
2
+ Name: skillscan-trace
3
+ Version: 0.1.0
4
+ Summary: Behavioral execution engine for MCP-based AI agent skills
5
+ Project-URL: Repository, https://github.com/kurtpayne/skillscan-trace
6
+ Project-URL: Issues, https://github.com/kurtpayne/skillscan-trace/issues
7
+ Project-URL: skillscan-security, https://github.com/kurtpayne/skillscan-security
8
+ License: MIT
9
+ Keywords: agents,ai,behavioral-analysis,mcp,security
10
+ Classifier: Development Status :: 2 - Pre-Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Topic :: Security
15
+ Requires-Python: >=3.11
16
+ Requires-Dist: bashlex>=0.18
17
+ Requires-Dist: click>=8.0
18
+ Requires-Dist: jsonschema>=4.0
19
+ Requires-Dist: mcp>=1.0
20
+ Requires-Dist: openai>=1.0
21
+ Requires-Dist: python-dotenv>=1.0
22
+ Requires-Dist: python-frontmatter>=1.0
23
+ Requires-Dist: pyyaml>=6.0
24
+ Requires-Dist: requests>=2.0
25
+ Requires-Dist: rich>=13.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: httpx>=0.27; extra == 'dev'
28
+ Requires-Dist: mypy>=1.0; extra == 'dev'
29
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
30
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
31
+ Requires-Dist: pytest>=7.0; extra == 'dev'
32
+ Requires-Dist: ruff>=0.1; extra == 'dev'
33
+ Provides-Extra: serve
34
+ Requires-Dist: fastapi>=0.110; extra == 'serve'
35
+ Requires-Dist: pydantic>=2.0; extra == 'serve'
36
+ Requires-Dist: uvicorn[standard]>=0.29; extra == 'serve'
37
+ Description-Content-Type: text/markdown
38
+
39
+ # skillscan-trace
40
+
41
+ [![CI](https://github.com/kurtpayne/skillscan-trace/actions/workflows/ci.yml/badge.svg)](https://github.com/kurtpayne/skillscan-trace/actions/workflows/ci.yml)
42
+ [![CodeQL](https://github.com/kurtpayne/skillscan-trace/actions/workflows/codeql.yml/badge.svg)](https://github.com/kurtpayne/skillscan-trace/actions/workflows/codeql.yml)
43
+ [![PyPI](https://img.shields.io/pypi/v/skillscan-trace.svg)](https://pypi.org/project/skillscan-trace/)
44
+ [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
45
+ [![Python](https://img.shields.io/badge/python-3.11%2B-blue.svg)](pyproject.toml)
46
+
47
+ **Behavioral execution engine for MCP-based AI agent skills.**
48
+
49
+ skillscan-trace runs a skill against a real language model inside an instrumented, isolated environment and records everything the model does: every file it reads, every network request it makes, every environment variable it accesses, every binary it probes. The output is a structured, machine-readable trace report.
50
+
51
+ It is the dynamic analysis counterpart to [skillscan](https://github.com/kurtpayne/skillscan-security), which performs static analysis. Together they form two legs of the skillscan family:
52
+
53
+ ```
54
+ skillscan family
55
+ ├── skillscan — static analysis (pattern matching, ML classifier)
56
+ ├── skillscan-trace — behavioral execution engine ← this repo
57
+ └── skillscan-lint — schema and format validation (planned)
58
+ ```
59
+
60
+ ---
61
+
62
+ ## What it does
63
+
64
+ A skill is a Markdown file that becomes a system prompt for an AI agent. Most skills are benign. Some are malicious — they instruct the agent to exfiltrate credentials, probe the filesystem, call attacker-controlled servers, or hijack the agent's behavior through prompt injection embedded in tool output.
65
+
66
+ Static analysis catches the obvious cases. Behavioral analysis catches the rest: conditional payloads that only activate in certain environments, obfuscated instructions that decode at runtime, and prompt injection delivered through external content the skill fetches.
67
+
68
+ skillscan-trace works by:
69
+
70
+ 1. Loading the skill's `SKILL.md` as the system prompt for a local language model
71
+ 2. Sending a realistic user prompt that exercises the skill's stated functionality
72
+ 3. Driving the model's tool-use loop through an **instrumented MCP server** that intercepts every tool call
73
+ 4. Checking each call against a canary taxonomy (credential files, wallet paths, ENV vars, binary probing, network destinations)
74
+ 5. Emitting a structured trace report (JSON + SARIF) with every observed behavior and any findings
75
+
76
+ The model runs locally via [Ollama](https://ollama.com/) — no API key required, no cloud dependency. API providers (OpenAI, OpenRouter, Anthropic) are supported for users who prefer them or want access to more capable models.
77
+
78
+ ---
79
+
80
+ ## Status
81
+
82
+ **v0.1.0 — core CLI complete.** Phases 1–5 are implemented and 144/144 tests pass. The tool is installable and usable today.
83
+
84
+ See [`SPEC.md`](./SPEC.md) for the full behavioral specification.
85
+ See [`ARCHITECTURE.md`](./ARCHITECTURE.md) for the system design.
86
+ See [`IMPLEMENTATION_PLAN.md`](./IMPLEMENTATION_PLAN.md) for the build plan and phase status.
87
+
88
+ ---
89
+
90
+ ## Quick start
91
+
92
+ ```bash
93
+ # Install from source
94
+ git clone https://github.com/kurtpayne/skillscan-trace
95
+ cd skillscan-trace
96
+ pip install -e .
97
+
98
+ # Run a trace with OpenAI
99
+ export OPENAI_API_KEY=sk-...
100
+ skillscan-trace run ./path/to/skill/
101
+
102
+ # Run with OpenRouter (200+ models via one key)
103
+ export OPENROUTER_API_KEY=sk-or-...
104
+ skillscan-trace run ./skill/ --provider openrouter --model mistralai/mistral-7b-instruct
105
+
106
+ # Run with a local Ollama model (no API key required)
107
+ skillscan-trace run ./skill/ --provider ollama --model qwen2.5:7b
108
+
109
+ # Run with explicit base URL (Azure, Mistral, etc.)
110
+ skillscan-trace run ./skill/ --base-url https://api.mistral.ai/v1 --api-key $MISTRAL_KEY
111
+
112
+ # Output formats
113
+ skillscan-trace run ./skill/ --format sarif # SARIF 2.1.0 for CI
114
+ skillscan-trace run ./skill/ --format json # native trace format
115
+ skillscan-trace run ./skill/ --format text # human-readable summary
116
+
117
+ # Verify connectivity
118
+ skillscan-trace check
119
+ skillscan-trace check --provider openrouter
120
+ skillscan-trace check --provider ollama
121
+ ```
122
+
123
+ ---
124
+
125
+ ## Skill format support
126
+
127
+ skillscan-trace handles all skill formats found in the wild:
128
+
129
+ | Format | Description | Example |
130
+ |---|---|---|
131
+ | Single `SKILL.md` | Standard Claude Code / MCP skill | `./my-skill/SKILL.md` |
132
+ | Single `.md` file | Flat file, no directory | `./my-skill.md` |
133
+ | Directory with `SKILL.md` | Standard with supporting files | `./my-skill/` |
134
+ | Frontmatter + body | YAML frontmatter + Markdown body | `name:`, `allowed-tools:` |
135
+ | Plain Markdown | No frontmatter | Any `.md` file |
136
+ | Multi-file skill | Directory with multiple `.md` files | Loaded in alphabetical order |
137
+
138
+ ---
139
+
140
+ ## Output: Trace Report
141
+
142
+ Every trace produces a JSON trace report and optionally a SARIF report.
143
+
144
+ ```json
145
+ {
146
+ "schema_version": "1.0.0",
147
+ "trace_id": "trc_20260320_abc123",
148
+ "skill": {
149
+ "path": "./my-skill/SKILL.md",
150
+ "name": "git-helper",
151
+ "sha256": "a1b2c3..."
152
+ },
153
+ "model": {
154
+ "provider": "ollama",
155
+ "model": "qwen2.5:7b",
156
+ "version": "..."
157
+ },
158
+ "prompt": "Help me commit my changes",
159
+ "duration_ms": 4823,
160
+ "tool_calls": [...],
161
+ "findings": [...],
162
+ "summary": {
163
+ "total_tool_calls": 7,
164
+ "finding_count": 1,
165
+ "severity_max": "HIGH",
166
+ "clean": false
167
+ }
168
+ }
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Relationship to skillscan-security
174
+
175
+ skillscan-trace is a sibling project to [skillscan-security](https://github.com/kurtpayne/skillscan-security). The two projects share:
176
+
177
+ - **Finding schema**: The same finding IDs (`EXF-001`, `MAL-001`, `IOC-001`, etc.) and severity levels
178
+ - **Canary taxonomy**: The same list of high-value target paths and ENV var names
179
+ - **Domain allowlist**: `trace/domains/verified.yml` from skillscan-security is the source of truth; skillscan-trace consumes it
180
+ - **Corpus feedback loop**: Traces that produce findings can be reviewed and added to the skillscan-security corpus as `sandbox_verified/` examples, improving the ML classifier's recall on behavioral patterns that static analysis misses
181
+
182
+ ---
183
+
184
+ ## Privacy & Key Handling
185
+
186
+ Your API key goes directly to the LLM provider you chose. The canary server runs in-process on your machine. Nothing leaves your network except the LLM API calls you explicitly authorize. SkillScan has no server-side component in local mode.
187
+
188
+ See [`PRIVACY.md`](./PRIVACY.md) for the full data flow explanation.
189
+
190
+ ---
191
+
192
+ ## Contributing
193
+
194
+ See [`CONTRIBUTING.md`](./CONTRIBUTING.md).
195
+
196
+ ---
197
+
198
+ ## License
199
+
200
+ MIT
@@ -0,0 +1,95 @@
1
+ # Privacy & Key Handling
2
+
3
+ skillscan-trace is a local tool. **Your skill files, API keys, and trace results never leave your machine** except for the LLM API calls you explicitly authorize.
4
+
5
+ ---
6
+
7
+ ## What happens during a trace
8
+
9
+ When you run `skillscan-trace run ./skill.md`, the following happens entirely on your machine:
10
+
11
+ 1. **Skill loading.** The skill file is read from your local filesystem. It is not uploaded anywhere.
12
+ 2. **Canary environment setup.** A temporary directory is created in-process with synthetic credential files, wallet paths, and environment variables. These are randomly generated per run and have no real value.
13
+ 3. **LLM API call.** The skill's content is sent to the LLM provider you configured (`--provider openai`, `--provider openrouter`, or `--provider ollama`). This is the only network request skillscan-trace makes. The request goes directly from your machine to the provider — it does not pass through any SkillScan server.
14
+ 4. **Canary server.** The instrumented MCP server runs in-process. It intercepts every tool call the model makes and checks it against the canary taxonomy. No subprocess is spawned; no data is written to disk except the trace report you explicitly request.
15
+ 5. **Report output.** The trace report is written to your local `./trace-output/` directory (or the path you specify with `--output-dir`). It is not uploaded anywhere.
16
+
17
+ ---
18
+
19
+ ## Your API key
20
+
21
+ Your API key is passed directly to the LLM provider you chose. It is not:
22
+
23
+ - Stored by skillscan-trace (it is read from your `.env` file, environment variable, or `--api-key` flag and used only for the duration of the run)
24
+ - Transmitted to any SkillScan server (there is no SkillScan server in local mode)
25
+ - Logged to disk (the trace report does not include your API key)
26
+ - Shared with any third party other than the LLM provider you selected
27
+
28
+ If you use `--provider openrouter`, your key goes to [OpenRouter](https://openrouter.ai). If you use `--provider openai`, it goes to [OpenAI](https://openai.com). If you use `--provider ollama`, no key is required and no network request is made to any external service.
29
+
30
+ ### Storing keys in .env
31
+
32
+ skillscan-trace reads a `.env` file automatically from the current directory and all parent directories (nearest file wins). This is the recommended way to store API keys:
33
+
34
+ ```
35
+ # .env — add this file to .gitignore, never commit it
36
+ OPENAI_API_KEY=sk-...
37
+ OPENROUTER_API_KEY=sk-or-...
38
+ ANTHROPIC_API_KEY=sk-ant-... # only needed when --judge is enabled
39
+ ```
40
+
41
+ Priority order (highest wins):
42
+ 1. `--api-key` CLI flag
43
+ 2. Shell environment variable (`export OPENAI_API_KEY=...`)
44
+ 3. `.env` file in the current or nearest ancestor directory
45
+ 4. `skillscan-trace.yaml` config file (API keys are **not** supported here — use `.env` instead)
46
+
47
+ The `.env` file is loaded with `override=False`, meaning shell variables you have already exported always take precedence over `.env` values. If no `.env` file is found, skillscan-trace falls back to the shell environment silently.
48
+
49
+ ---
50
+
51
+ ## What is sent to the LLM provider
52
+
53
+ The LLM API call contains:
54
+
55
+ - The skill's `SKILL.md` content (as the system prompt)
56
+ - A generated user message that exercises the skill's stated functionality
57
+ - The canary tool definitions (the list of tools the model can call)
58
+
59
+ The canary tool definitions describe the tool interface (names, parameter schemas) but do not contain any real credential values. The canary values (fake AWS keys, fake wallet seeds, etc.) are only present in the tool *responses* that the canary server returns when the model calls a tool — those responses stay on your machine and are never sent back to the LLM provider in a way that would expose them.
60
+
61
+ ---
62
+
63
+ ## Ollama (fully local)
64
+
65
+ If you use `--provider ollama`, the entire trace runs on your machine with no external network requests. The model runs locally via [Ollama](https://ollama.com/). No API key is required. No data leaves your machine.
66
+
67
+ ---
68
+
69
+ ## Trace reports
70
+
71
+ Trace reports (JSON, SARIF, text) are written to your local filesystem only. They contain:
72
+
73
+ - The skill path and SHA-256 hash of the skill content
74
+ - The model and provider used
75
+ - All tool calls the model made (tool name, arguments, canary server response)
76
+ - Any findings (rule ID, severity, description)
77
+ - Token usage for the run
78
+
79
+ They do not contain your API key, your system's real credential files, or any data from outside the canary environment.
80
+
81
+ ---
82
+
83
+ ## Summary
84
+
85
+ | Data | Where it goes |
86
+ |---|---|
87
+ | Skill file content | LLM provider (as system prompt) |
88
+ | API key | LLM provider only (never stored or logged) |
89
+ | Canary tool definitions | LLM provider (tool schemas, no real values) |
90
+ | Canary credential values | Your machine only (in-process canary server) |
91
+ | Trace report | Your local filesystem only |
92
+ | Your real credential files | Not accessed (canary uses synthetic files) |
93
+ | `.env` file contents | Your machine only (never transmitted) |
94
+
95
+ If you have questions or concerns about data handling, open an issue at [github.com/kurtpayne/skillscan-trace](https://github.com/kurtpayne/skillscan-trace/issues).