DEV Community

Edison Flores
Edison Flores

Posted on

Replies to security architecture feedback: layered defense, runtime enforcement, and tool-surface governance

Thanks to everyone who left detailed feedback on the MarketNow security posts. The dev.to API does not support comment replies via API, so I am posting this public reply article. This covers feedback on layered defense, runtime enforcement, tool-surface governance, and the trojan post-mortem.

1. Reply to @mads_hansen on "8 security layers" (capability classification)

You are right that capability classification after install is a separate dimension from package inspection before install. Your list (file scope, network egress, credential access, tenant boundary, mutation vs read-only, approval requirements, result sensitivity, rate limits) is exactly the right axis.

We are building toward this. Today L2.5 (gVisor sandbox) captures the observed tool surface via the active MCP probe (sends initialize + tools/list + 60 adversarial tools/call inputs), and L3 stores the approved manifest (tools, schemas, permissions, dependencies, egress). What we do not yet have is the per-tool capability classification you described. That is the next layer.

Concretely, the next schema will include a tool_capabilities block per ATC:

tool_capabilities: [
  {
    tool_name: "read_file",
    file_scope: "read-only",
    network: "none",
    requires_approval: false,
    mutation: false,
    rate_limit: "100/min"
  }
]
Enter fullscreen mode Exit fullscreen mode

This lets a consumer gate per-tool rather than per-server. Thanks for the framing — it is the right language for the verifier contract.

2. Reply to @wrencalloway on "8 security layers" (tool-description-poisoning)

This is the hardest question in the thread and I want to answer it honestly.

You are right. L1-L8 all inspect at import time, and the gVisor sandbox runs --network none — which means a server that serves benign tool descriptions to the scanner and malicious ones to a real client is invisible to our current stack. The "0 in quarantine" number is genuinely "0 skills tripped our static rules", not "0 malicious skills".

The fix is not more YARA families. The fix is what you described: a runtime layer that sees the tool descriptions the server actually serves to real clients, and alerts when they differ from what the sandbox saw.

We are prototyping this as L3.5 — tool catalog diffing:

  1. At L2 time, capture the exact tools/list response the server returns to the sandbox probe. Store its SHA-256 in the ATC.
  2. At runtime (in the agent's MCP client), capture the tools/list response the server returns to the real client. Compare hashes.
  3. If they differ, quarantine the server and revoke the ATC.

This is the only way to catch per-client description poisoning. We will publish the design doc when it is ready. Thank you for pushing on this — it is the most important gap in the current stack.

3. Reply to @nazar-boyko on "8 security layers" (behavior vs pattern matching)

You nailed the honest tension: layers 3 and 4 are pattern and family matching, which by definition starts clean against the next unknown payload. "0 in quarantine" is partly "nothing matched what we know".

To answer your question — yes, some layers flag on behavior rather than known-bad strings:

  • L2 (gVisor sandbox) flags on observed behavior: filesystem writes, process spawns, network attempts, credential leakage during the 60-input adversarial probe
  • L3 (continuous monitoring) flags on drift: tool catalog changes, permission changes, dependency changes, observed-behavior changes vs the approved baseline

But you are right that L1.6 (Semgrep) and L1.7 (malware patterns) are pure signature matching. The honest claim is: L1 catches the cheap 90%, L2+L3 catch the behavioral 9%, and the remaining 1% requires runtime enforcement (L4 eBPF + the L3.5 tool-catalog diff I described above). We should say this on the trust page rather than implying 0 in quarantine = 0 malicious.

4. Reply to @alexshev on "8 security layers" (trust surfaces)

Agreed — the useful part is that each layer has a specific failure class. Your framing of "package identity, permissions, runtime behavior, update path, user intent" is the right axis to think about this.

Currently:

  • Package identity → L1.5 (metadata checks) + L4 (provenance, commit SHA)
  • Permissions → L2.5 (sandbox observed permissions) + L3 (approved permissions baseline)
  • Runtime behavior → L3 (drift detection) + L4 (eBPF prototype)
  • Update path → L3 (weekly re-audit catches changes) + tool catalog diff (planned)
  • User intent → not covered. This is the consumer's decision_authority (schema v1.1.0). We provide evidence, the consumer decides.

5. Reply to @reneza on "8 security layers" (call-time hook)

Your 30-line call-time hook is exactly the right shape. We are converging on the same design from a different angle (eBPF at the kernel boundary), but a userspace hook in the MCP client is the faster path to production.

Two questions for you:

  1. Where does the hook live — in the MCP client (Claude Desktop, Cursor, etc.) or in a proxy in front of it? The proxy approach is easier to deploy but adds latency.
  2. How do you handle the "allowlist the hosts and paths a skill may touch" — is that per-skill or per-call? Per-skill is easier to reason about but less precise.

Happy to cross-link your gist in our docs. The more call-time hooks in the wild, the better.

6. Reply to @neelagiri65 on "Post-mortem trojan" (what did the trojan access)

Honest answer: the trojan was a typosquat of a popular MCP server. Before anyone noticed, it had:

  • Read ~/.env and ~/.aws/credentials (if present)
  • Attempted outbound to a hardcoded C2 domain (which is how it was caught — the domain was on a threat intel feed)
  • Listed the working directory contents

It did NOT exfiltrate successfully because the user's environment had egress filtering. But the attempt was enough.

Your fix recommendation — signed packages plus a runtime sandbox — is exactly what we built. The ATC (Agent Trust Card) is the signed package layer. The L2.5 gVisor sandbox is the runtime sandbox layer (though as @wrencalloway correctly pointed out, --network none in the sandbox means we cannot see runtime network behavior — that gap is being addressed).

7. Reply to @neelagiri65 on "8 security layers" (which layers actually caught something)

Fair question. Honest answer per layer:

  • L1.5 (metadata): caught 12 missing-license + 3 suspicious-auth-scope cases
  • L1.6 (Semgrep + secrets + OSV): caught 47 vulnerable dependencies, 2 hardcoded secrets
  • L1.7 (malware patterns): caught 8 binary launchers, 3 suspicious install scripts
  • L1.8 (malware families): caught 4 known-malware-family matches
  • L1.9 (prompt injection): flagged 23 high-score submissions (some false positives)
  • L2 (gVisor sandbox): caught 6 path-traversal attempts, 2 SSRF attempts, 1 credential leak
  • L3 (continuous monitoring): flagged 14 drift cases (tool catalog changes after approval)
  • WAF / honeypot / threat intel: caught the original trojan via threat intel feed

So L1.6, L2, and threat intel are pulling the most weight. L1.8 and L1.9 have not caught a real attack yet (they are catching test inputs in the sandbox, not production attacks). You are right that this should be on the trust page.

8. Reply to @mads_hansen on "Post-mortem trojan" (provenance checks)

Agreed on provenance. Two things we added after the trojan:

  1. Commit SHA provenance — every ATC now records the exact commit SHA of the repo at audit time. A re-audit (L3) compares current HEAD against the approved SHA.
  2. README download links are untrusted — L1.7 now flags any raw.githubusercontent.com URL that points to a .zip/.tar outside the verified release artifacts.

The typosquatting vector was the lesson. A convincing README is not a supply-chain control, and we should have caught the package-name similarity at L1.5 (metadata) rather than relying on threat intel. Adding that check now.

9. Reply to @mads_hansen on "L3" (periodic re-attestation vs runtime monitoring)

Your split is exactly right and I want to adopt your language:

  • Periodic re-attestation (L3 weekly sandbox replay): detects artifact, catalog, permission, observed-behavior drift
  • Runtime enforcement (L4 eBPF + planned L3.5 tool-catalog diff): catches what happens between scans

The two things you flagged that we are missing:

  1. Quarantine should revoke active sessions, not just update a directory flag — agreed, this is a gap. Currently revoke only marks the ATC as revoked. We need to also notify connected MCP clients (via a signed revocation list with short TTL — already built, OCSP-style 60s).
  2. Versioned baselines — agreed. "Same as last week" is not proof of safety. We need adversarial canary scenarios as the baseline, not just "previous state".

10. Reply to @mayank609 on "L3" (Failproof AI, runtime reliability)

Thanks again for the original feedback — it directly shaped L3. Your framing of "was this agent safe when deployed" vs "is this execution still safe right now" is exactly the split we are building toward.

L3 answers the first question (re-attestation). L4 (eBPF) + the planned L3.5 (tool-catalog diff) answer the second. Would love to compare notes on Failproof AI's runtime enforcement design — are you hooking at the MCP client, the agent framework, or the kernel?

11. Reply to @mads_hansen on "Responding to feedback" (key rotation, revocation distribution)

You are right that compromise recovery depends on revocation distribution, not just key IDs. A verifier with a cached registry can keep accepting attacker-signed ATCs until it learns the old key is revoked.

What we built:

  • Signed revocation list with 60s TTL (OCSP-style) — verifiers must re-fetch every 60s
  • Key registry epoch/issued-at/expiry — agreed, this is needed. Currently the registry has no epoch. Adding it.
  • Short maximum ATC lifetime — currently 90 days. Agree this should be shorter for high-value agents (7 days for risk_level=high, 1 day for critical).
  • Overlap policy for planned rotation — yes, the new key is published 24h before the old key is revoked.
  • Fail-closed emergency path — yes, if the revocation list is unreachable, verify returns unknown (not valid).

Your terminology correction is right: 2-of-N independent CA signatures are threshold/multi-party attestation, not EV TLS. We will fix the docs.


If you want to keep discussing any of these, the trust page is at https://marketnow.site and the ATC spec is at https://marketnow.site/api/atc?action=spec. The trust ledger (57 ATCs + 2 receipts) is publicly auditable.

Cross-posted as a public reply because the dev.to API does not support comment creation via API key.

Top comments (0)