@rexymayderio/sentinel
v0.2.0
Published
Universal Security Verification Framework for AI Agent Installations
Downloads
1,083
Maintainers
Readme
Sentinel
Universal Security Verification Framework for AI Agent Installations
Sentinel sits between an AI agent (or a human) and any installer. Nothing installs until the target has been acquired (download-only, never executed), analyzed, risk-scored, policy-checked, and explicitly approved.
Playground · GitHub repository
flowchart TD
A[AI / User] --> B[Sentinel]
B --> C[Acquire]
C --> D[Analyze]
D --> E[Score]
E --> F[Policy]
F --> G[Approve]
G --> H[Install]The installer never runs directly. Acquirers only download and read files; install scripts are never executed during analysis.
Installation
npm install
npm run buildOr install globally / run via npx after publishing:
npm install -g @rexymayderio/sentinel
sentinel verify npm express
# MCP server (use -p so npx runs the sentinel-mcp bin, not the CLI)
npx -y -p @rexymayderio/sentinel sentinel-mcpRequires Node.js >= 20.
Usage
CLI
# Verify only (never installs) - the manual verification path
sentinel verify npm express
sentinel verify github owner/repo
sentinel verify skill ./my-skill
sentinel verify local ./some-directory
sentinel verify mcp @modelcontextprotocol/server-filesystem
sentinel verify vscode publisher.extension
sentinel verify cursor-rules ./.cursor/rules
sentinel verify zip ./download.zip
# Verify, then install behind the approval gate
sentinel install npm express
sentinel install mcp @modelcontextprotocol/server-filesystem
sentinel install skill ./my-skill --yes # auto-approve (still cannot override a hard BLOCK)
# Output formats
sentinel verify npm express --json
sentinel verify npm express --markdown
sentinel verify npm express --sarif
# Custom policy file
sentinel verify npm express --policy ./policy.json
# Scan test/fixture files with the full ruleset (default: secrets + malware only)
sentinel verify local ./my-project --score-tests
# CLI help
sentinel help
sentinel verify --helpDuring local development you can run without building:
npm run dev -- verify skill ./my-skillMCP server
npm run mcpExample MCP client config:
{
"mcpServers": {
"sentinel": {
"command": "npx",
"args": ["-y", "-p", "@rexymayderio/sentinel", "sentinel-mcp"]
}
}
}The
-p @rexymayderio/sentinel(package) flag is required: it tellsnpxto run thesentinel-mcpbinary from the package. Without-p,npx @rexymayderio/sentinel sentinel-mcpwould run the CLI withsentinel-mcpas an (invalid) argument.
CLI vs MCP
Both ship in the same @rexymayderio/sentinel package - installing it provides two binaries:
| Binary | Purpose | Run |
|--------|---------|-----|
| sentinel | Command-line verifier/installer | npx -y -p @rexymayderio/sentinel sentinel verify npm express |
| sentinel-mcp | MCP server over stdio for AI agents | npx -y -p @rexymayderio/sentinel sentinel-mcp |
There is no separate "CLI-only" or "MCP-only" download - the two binaries are lightweight symlinks over a shared engine, so one install covers both. Use whichever entry point you need.
MCP tools: verify_package, verify_repository, verify_skill, verify_mcp, verify_extension, verify_cursor_rules, verify_docker, calculate_risk, generate_report, scan_directory, scan_archive, approve_install, install.
MCP policy can be configured with SENTINEL_POLICY_JSON and full test scoring with
SENTINEL_SCORE_TESTS=true. Restrict local reads and install destinations with
the platform-delimited SENTINEL_ALLOWED_ROOTS environment variable. Docker verification returns an explicit
supported: false response and never masquerades as a completed scan.
Agent Skill
Install the Sentinel agent skill so your AI assistant intercepts install requests, verifies via the MCP above, explains risks, and only installs after approval.
Copy or symlink skills/sentinel/SKILL.md into your agent's skills directory (e.g. ~/.cursor/skills/sentinel/SKILL.md for Cursor).
The skill never performs analysis itself — it routes to the Sentinel MCP tools and interprets the JSON report. Manual /verify-* commands and automatic install interception are documented in the skill file.
Supported targets
| Target | Status | Notes |
|--------|--------|-------|
| npm | Implemented | Registry metadata + tarball extraction |
| github | Implemented | Repo metadata + tarball download |
| skill | Implemented | Local AI skill folder / SKILL.md |
| local | Implemented | Any local directory |
| mcp | Implemented | npm-backed MCP package + immutable npm identity |
| vscode | Implemented | Marketplace VSIX download + bounded ZIP extraction |
| cursor-rules | Implemented | Local Cursor rule directory, including .mdc files |
| zip | Implemented | Local ZIP / VSIX with traversal, symlink, count, and size guards |
| pip, uv, cargo, go, docker, git | Not yet implemented | Acquisition fails -> REQUIRE_APPROVAL (manual review) |
How risk is scored
Each finding has a severity. The Risk Calculator sums severity weights, subtracts positive-signal credit, and clamps the result to 0-100.
| Severity | Weight |
|----------|--------|
| CRITICAL | +50 |
| HIGH | +20 |
| MEDIUM | +10 |
| LOW | +2 |
| INFO | 0 |
Positive signals (verified publisher, long history, etc.) each subtract 5 from
LOW/MEDIUM signal weight, capped at -30; they never offset HIGH or CRITICAL findings.
Test/fixture code is detected by path (test/, tests/, __tests__/, fixtures/, *.test.*, *.spec.*, etc.) and scanned with a narrower ruleset than production code. Everyday dev patterns (child_process, spawn, eval, dynamic imports, rm -rf, ...) are expected in tests and are not flagged there. Instead, test files are checked only for the things that genuinely matter in tests — the places malware likes to hide:
- Leaked secrets (AWS/GCP/OpenAI keys, private keys, tokens, ...)
- Malware signatures: remote payload delivery (
curl … | sh,wget … | sh), crypto miners, UPX-packed blobs - Exfiltration / C2 channels: Discord/Telegram webhooks, Pastebin, ngrok, Cloudflare tunnels,
.onion, dynamic DNS - Prompt-injection attacks hidden in fixtures
Findings that survive this filter are real, so they are reported (tagged [test-file] in terminal output, isTest: true in JSON) and counted at full weight in the risk score and policy. Use --score-tests (or set scoreTestCodeFully: true in policy) to scan test files with the full production ruleset instead.
The final score maps to a risk level:
| Score | Risk level |
|-------|------------|
| 0-19 | LOW |
| 20-49 | MEDIUM |
| 50-79 | HIGH |
| 80-100 | CRITICAL |
Confidence reflects how much evidence was actually gathered, not how many problems were found. A clean, fully-described package is high confidence even with zero findings. It is computed from:
- package metadata present (
+35) - at least one file scanned (
+25), plus+2per file up to+20 +2per finding signal up to+20
clamped to 0-100. When acquisition fails entirely, confidence is 0. Confidence (and whether any files/metadata were gathered) feeds the data-sufficiency check that can escalate a target to REQUIRE_APPROVAL.
Policy decisions
The Policy Engine (src/engine/policy-engine.ts) reduces the risk score, findings, permissions, and data assessment into exactly one of the five POLICY_DECISIONS. They are evaluated in a fixed priority order and the first matching rule wins.
Evaluation order:
- Corporate blacklist ->
BLOCK - Risk score >= block threshold ->
BLOCK - Insufficient data ->
REQUIRE_APPROVAL - Any HIGH / CRITICAL finding ->
REQUIRE_APPROVAL - Corporate whitelist ->
AUTO_APPROVE - Verified / trusted publisher ->
AUTO_APPROVE - Install script / shell / network / filesystem-write / warn-threshold checks ->
WARNorREQUIRE_APPROVAL - Nothing flagged ->
APPROVE
AUTO_APPROVE
- Meaning: Sentinel is confident the target is safe; no human interaction needed.
- Triggered when: hard blocks, data checks, and severe-finding checks pass, then the package matches
corporateWhitelist; orautoApproveTrustedis enabled and a trusted signal matches. - Risk shown: actual level (typically
LOW). - Recommended action:
SAFE TO INSTALL. - Install behavior: proceeds without prompting (CLI and MCP).
APPROVE
- Meaning: No policy violations detected, but not explicitly trusted either. Safe default.
- Triggered when: the target passes all checks - below warn threshold, no install scripts, no shell access, no gated network or filesystem-write access, sufficient data.
- Risk shown: actual level.
- Recommended action:
SAFE TO INSTALL. - Install behavior: CLI prompts for confirmation unless
--yesis passed; MCPinstallproceeds whenconfirm: true.
WARN
- Meaning: Installable, but something deserves attention.
- Triggered when:
warnOnInstallScriptis on and an npm/MCP package defines consumer lifecycle scripts (preinstall/install/postinstall), ORwarnOnShellAccessis on and shell access was detected (and not already escalated), OR the risk score is at/abovewarnThreshold(default 50). - Risk shown: actual level.
- Recommended action:
PROCEED WITH CAUTION. - Install behavior: CLI prompts (the
--yesflag asserts human approval). MCP requires bothconfirm: trueandhumanApproved: true.
REQUIRE_APPROVAL
- Meaning: A human must explicitly approve - either because a sensitive capability was detected, or because Sentinel could not gather enough data to judge the target on its own.
- Triggered when: any of:
warnOnShellAccessdetects shell access (escalated from the default);requireApprovalForNetworkis on and a network permission / non-LOWnetwork finding is present;requireApprovalForFilesystemWriteis on and runtime code can modify the filesystem;- the data assessment (
src/engine/data-assessment.ts) is insufficient - acquisition failed (network error, package not found, unsupported ecosystem), no files could be scanned, a remote target returned no usable metadata, or analysis confidence is belowminConfidence(default 40%). In this case the report'sdataAssessmentlists the specific reasons.
- Risk shown: actual level (may be
LOWwith low confidence when data is thin). - Recommended action:
REVIEW AND APPROVE BEFORE INSTALLING. - Install behavior: CLI prompts for explicit
y/N;--yesasserts human approval. MCP requireshumanApproved: truein addition to installation intent.
BLOCK
- Meaning: Installation is forbidden. Cannot be overridden by
--yesor by the MCPconfirmflag. - Triggered when: the package name matches the
corporateBlacklist, OR the risk score is at/aboveblockThreshold(default 80, i.e.CRITICAL). - Risk shown: actual level (typically
CRITICAL). - Recommended action:
DO NOT INSTALL. - Install behavior: refused everywhere. CLI exits with code
2.
Decision summary
| Decision | Trigger | Risk shown | Recommended action | Auto-installable |
|----------|---------|------------|--------------------|------------------|
| AUTO_APPROVE | Whitelist / verified / trusted publisher | actual | SAFE TO INSTALL | Yes |
| APPROVE | No violations | actual | SAFE TO INSTALL | With confirm/--yes |
| WARN | Install script or warn-threshold | actual | PROCEED WITH CAUTION | With human approval |
| REQUIRE_APPROVAL | Shell/network/filesystem-write access, severe findings, or insufficient data | actual | REVIEW AND APPROVE BEFORE INSTALLING | With human approval |
| BLOCK | Blacklist or score >= block threshold | actual | DO NOT INSTALL | No |
Policy configuration
Pass a JSON file via --policy <file> to override defaults (src/engine/default-policy.ts).
| Field | Type | Default | Effect |
|-------|------|---------|--------|
| blockThreshold | number | 80 | Score at/above this -> BLOCK. |
| warnThreshold | number | 50 | Score at/above this -> at least WARN. |
| minConfidence | number | 40 | Confidence below this -> data treated as insufficient -> REQUIRE_APPROVAL. |
| trustedPublishers | string[] | [] | Exact names or explicit scoped prefixes ending in / or /*. |
| corporateWhitelist | string[] | [] | Exact names/scoped prefixes auto-approved only after hard blocks and data checks. |
| corporateBlacklist | string[] | [] | Exact names/scoped prefixes forced to BLOCK. |
| autoApproveTrusted | boolean | false | Opt in to verified/trusted-publisher auto-approval. |
| requireApprovalForNetwork | boolean | true | Network access -> REQUIRE_APPROVAL. |
| requireApprovalForFilesystemWrite | boolean | true | Filesystem mutation capability -> REQUIRE_APPROVAL. |
| warnOnInstallScript | boolean | true | Install scripts -> WARN. |
| warnOnShellAccess | boolean | true | Shell access -> REQUIRE_APPROVAL. |
| allowOverrides | boolean | true | Allow human overrides of non-BLOCK decisions. |
| scoreTestCodeFully | boolean | false | When false, test/fixture files are scanned only for leaked secrets and malware signatures. When true, they are scanned with the full production ruleset. |
Example policy.json:
{
"blockThreshold": 70,
"minConfidence": 50,
"trustedPublishers": ["@myorg/"],
"corporateBlacklist": ["leftpad-evil"]
}Analyzers
| Analyzer | Looks for |
|----------|-----------|
| Metadata | name, license, repo, first publish date, recent version update, downloads, verified publisher |
| Source | HTTPS, suspicious TLDs, npm typosquatting |
| Static code | eval, exec, spawn, child_process, subprocess, dynamic imports, base64/hex blobs, entropy, minified files |
| Runtime capability | Node.js filesystem read/write and network module access |
| Install script | consumer postinstall/preinstall/install, curl\|bash, wget\|bash, sudo, rm -rf, npx |
| AI prompt | prompt injection, zero-width / invisible Unicode, jailbreaks, hidden goals, memory poisoning, tool escalation |
| Secret | AWS / GCP / OpenAI / Anthropic / GitHub keys, JWT, private keys |
| Dependency | dependency count, insecure sources, local file deps, optional native packages, OSV lookups |
| Network | hardcoded IPs, Discord/Telegram webhooks, pastebin, ngrok, crypto miners, Tor |
| Binary | opaque native executables and WebAssembly that require manual inspection |
Reports include evidence for code-based findings: the matching source line (file, line number, and a snippet up to 120 characters). Terminal output shows this under each finding; JSON includes file, line, and evidence fields.
Development
npm run build # compile TypeScript to dist/
npm test # run behavioral tests (vitest)
npm run check # type-check source/tests and run the suite
npm run test:watch # watch mode
npm run validate:real -- all --summary # live 40-target precision/capability matrixArchitecture follows ports-and-adapters: analyzers, the risk calculator, and the policy engine are pure and unit-testable, while I/O boundaries (registry, repo API, process runner, approval prompt) are mocked in tests.
License
MIT
