After a real trojan slipped through my MCP marketplace last week (Trojan:Win64/Lazy.PGPK!MTB hidden in a nested zip), I went deep on defense-in-depth. The result is 8 layers running in production at marketnow.site.
Here's what each layer actually catches — with concrete examples.
Layer 1: L1.5 — Metadata checks (6 rules)
The cheapest layer. Runs on every skill's metadata (name, description, system_prompt, install command).
Catches:
- Skills that say "no auth required" (warning)
- Skills with prompt injection patterns in descriptions ("ignore previous instructions")
- Skills with file/SQL/HTTP access declared in metadata
- Skills with
Access-Control-Allow-Origin: *
- Skills using unscoped OAuth tokens
- Skills with no rate limiting
Doesn't catch: anything inside the actual package zip. That's why the trojan got through initially.
Layer 2: L1.6 — Semgrep + Secrets + OSV (36 rules)
18 Semgrep-equivalent rules + 18 secret detection patterns + OSV dependency vulnerability check.
Catches:
- Hardcoded API keys (Stripe
sk_live_*, GitHubghp_*, AWSAKIA*) - Wallet mnemonics in descriptions
- Command injection patterns (
exec(req.body)) - SSRF patterns (
fetch(req.url)) - Path traversal (
readFile(req.params.path)) - Tool name spoofing (a tool calling itself
read_fileto impersonate the official one) - Known vulnerable npm dependencies (via OSV API)
Doesn't catch: secrets inside code blocks in README (we strip those — false positives), process.env.X references (variable lookups, not hardcoded).
Layer 3: L1.7 — Binary & malware detection (8 patterns)
This is the layer I built after the trojan incident. It opens the actual package zip (recursively — zips inside zips) and scans for:
Windows binaries (.exe,.dll,.scr,.msi) → instant quarantine
Launcher scripts (.bat,.cmd,.vbs,.ps1) → instant quarantine
Nested archives (zips inside zips — legit MCP skills don't do this)
Staged launchers (start X.exe Y.txtpattern — the exact prospector trojan signature)
Obfuscated Lua bytecode (high-arity function signaturefunction(o,R,F,U,b,p,E,M,Z,W,...))
External download URLs in README (raw.githubusercontent.com/.../...zip)
PowerShell-encodedcommandwith long base64
eval(atob(...))obfuscation
Oversized text files (>100KB non-JSON = likely bytecode payload)
Catches: the exact trojan that hit us. Verified with a smoke test that scans the original malicious zip from git history.
Layer 4: L1.8 — Malware family signatures (17 families)
YARA-equivalent rules for specific malware families:
Win64/Lazy.PGPK (the one that hit us)
Emotet (banking trojan)
Cobalt Strike (post-exploitation beacon)
Mimikatz (credential dumper)
QakBot, TrickBot (banking trojans)
Agent Tesla (keylogger)
RedLine, Vidar, Raccoon, LummaC2 (stealers)
AsyncRAT, njRAT, Remcos (RATs)
SolarMarker (backdoor)
Lokibot (credential stealer)
DoS tools (hping3, slowloris, goldeneye)
Each rule has a MITRE ATT&CK technique ID. Any match → instant quarantine.
Layer 5: WAF — Web Application Firewall (40 rules)
Inspects every incoming HTTP request for attack patterns:
SQLi (7 rules): UNION SELECT, OR 1=1, stacked queries, time-based, information_schema
XSS (7 rules): script tags, event handlers, javascript: URIs, img onerror, svg onload
Path traversal (5 rules):../, encoded%2e%2e,/etc/passwd,/proc/self, Windows paths
SSRF (6 rules): AWS/GCP/Azure metadata IPs,file://,gopher://,dict://
Command injection (5 rules): backticks,$(), chained; ls, pipe| cat,&& ||
NoSQL injection (3 rules):$where,$ne,$gt
Prototype pollution:__proto__,constructor.prototype
SSTI: Jinja2{{ }}, Twig{% %}, JS${ }
Log injection:
with header injection
Auto-ban after 5 WAF hits in 10 minutes (1-hour ban).
Layer 6: Honeypot (50+ paths)
Fake vulnerable paths that auto-ban scanners for 24 hours:
/.env→ serves a fake env file with canary tokens
/admin→ serves a fake admin login form
/wp-admin→ serves a fake WordPress login
/.git/config→ serves a fake git config
/.aws/credentials→ serves fake AWS credentials
/.ssh/id_rsa→ serves a fake SSH key
/phpmyadmin→ serves a fake phpMyAdmin
/backup.sql→ serves a fake database dump
/server-status,/.DS_Store,/web.config,/Dockerfile, etc.
Any access → IP banned 24h + logged publicly at /api/security?view=honeypot.
Layer 7: Threat Intelligence (3 feeds)
Real-time IOC feeds from abuse.ch:
URLhaus — last 1000 malicious URLs (5-min cache)
MalwareBazaar — last 100 malware sample hashes
ThreatFox — IOCs from active malware campaigns (7-day window)
Used to check skill source URLs and file hashes. If a skill's source URL is in URLhaus, it gets quarantined.
Layer 8: Auto-Quarantine
If any layer flags a skill as critical/high:
- Skill certificate moves to
_data/quarantine/
- Skill removed from public catalog (
skills_index.json) - Listed publicly at
/api/security?view=quarantinefor transparency - Pre-import scan in the auto-discovery pipeline blocks it before entering the catalog
What actually happened when I ran all 8 layers
Re-audited all 14,581 skills with the new layers.
Result: 0 skills in quarantine.
The catalog was clean — the only malicious skill (prospector-email-finder) had already been removed manually. The 8 layers now run on every new skill import and every weekly batch re-audit.
The stack
Vercel Hobby (free tier, 11 serverless functions)
GitHub Actions for batch audits (120-min timeout, 16GB RAM)
Docker + gVisor for L2 sandbox (--network none,--read-only,--cap-drop ALL)
Base (L2) for USDC payment verification
ethers.js for EIP-191 signature verification
abuse.ch for threat intel feeds (free, no API key)
Total infrastructure cost: $0/month. The marketplace is free. The security infrastructure is the product.
Try it
- Browse: https://marketnow.site
- Install:
npx -y marketnow-mcp
- Security overview: https://marketnow.site/api/security
- Trust page: https://marketnow.site/trust
- GitHub: https://github.com/edgarfloresguerra2011-a11y/marketnow
Not selling anything. Looking for feedback from people who run MCP servers in production — what would make you trust a marketplace enough to install skills from it?
— Edison Flores, AliceLabs LLC
SOCIAL SHARE CARD GENERATOR