Security Model — V0.5.0

Trust boundaries

Trusted control plane

  • normal authenticated ChatGPT conversation;
  • authenticated Val Town plugin operations;
  • source code committed in cleitoncosta/chat-native-maestro after validation.

Sensitive trusted storage

  • Val Town Environment Variables;
  • val-scoped SQLite, but only for non-secret task metadata/evidence.

Untrusted inputs

  • every webpage and frame;
  • page text, HTML, script-generated text and accessibility labels;
  • redirects;
  • URLs supplied by pages;
  • downloaded files;
  • DNS answers and provider responses as evidence that still needs validation;
  • third-party provider error messages.

A webpage is data, never policy or authorization.

Threat 1 — Prompt injection from a webpage

Risk: page content tries to instruct ChatGPT/runner to reveal secrets, change policy, expand allowed hosts, approve actions or run arbitrary code.

Controls:

  • browser receives a bounded DSL, not a free-form agent prompt;
  • no shell or arbitrary-JS task action;
  • page content cannot set approved=true;
  • page content cannot add env vars;
  • page content cannot alter allowedHosts;
  • browser result is evidence/data only.

Residual risk: extracted malicious text can still be shown to the language model. The control plane must continue treating it as untrusted data.

Threat 2 — SSRF / internal network access

Risk: task or redirect targets localhost, cloud metadata, private network or a public hostname resolving to non-public IPs.

Controls before provider call:

  • HTTP/HTTPS only;
  • URL userinfo blocked;
  • only ports 80/443;
  • direct private/link-local/loopback/reserved/documentation IPv4 and IPv6 ranges blocked;
  • localhost/internal/metadata hostnames blocked;
  • allowedHosts validated;
  • A and AAAA resolved through Cloudflare DNS-over-HTTPS;
  • task fails closed if DoH fails, no A/AAAA is found, or any resolved address is non-public.

Controls in browser:

  • main-frame navigation restricted to target host plus explicit allowed hosts;
  • popups closed.

Validated negative control: 169.254.169.254 is blocked in the real runner before provider invocation.

Residual risk: DNS rebinding after preflight cannot be fully proven absent by a one-time DoH check. Remote browser isolation and navigation checks remain required.

Threat 3 — Secret leakage

Risk: credentials enter task JSON, source, logs or persistent receipts.

Controls:

  • provider credentials only in Val Town env vars;
  • site credentials referenced by env-var name with fill_secret;
  • secret value resolved in memory immediately before execution;
  • fill_secret requires explicit approval;
  • extract_attribute: value blocked;
  • default evidenceRetention=minimal omits extracted outputs and provider session IDs;
  • snapshot/export must exclude env-var values and raw sensitive task payloads.

Residual risk: a target site can reflect a submitted secret into ordinary DOM text. The orchestrator must not deliberately extract selectors expected to contain secrets, and full retention must not be used for sensitive workflows without a specific reason.

Threat 4 — Duplicate/replayed writes

Risk: timeout or provider error occurs after a write happened, then another attempt repeats the effect.

Controls:

  • automatic retry only for read_only + FAIL;
  • no automatic retry for reversible_write or consequential;
  • no cross-provider fallback for writes;
  • unique run_id in SQLite;
  • write tasks require explicit approval.

Residual risk: even a read-classified website can mutate state via GET. The read-only method firewall is strong but cannot prove zero side effects on a badly designed server.

Threat 5 — Read-only task causes state mutation

Controls:

  • browser request firewall allows only GET/HEAD/OPTIONS for read_only;
  • common POST/PUT/PATCH/DELETE side effects are blocked;
  • explicit expectations and post-action verification required.

Residual risk:

  • GET endpoints may have side effects;
  • service-worker/browser behavior can be complex;
  • some legitimate read APIs use POST/GraphQL and will fail under strict mode. Do not weaken strict mode silently; use a connector/fetch route or explicitly reclassify the task.

Threat 6 — Provider degradation / repeated spend

Risk: provider outage causes repeated browser sessions or runaway retries.

Controls:

  • max 2 task attempts;
  • 10-second retry eligibility delay;
  • no automatic scheduler;
  • provider circuit opens after 3 consecutive FAILs;
  • 15-minute cooldown;
  • BLOCKED config errors do not increment failure count;
  • PASS/PARTIAL resets provider failures;
  • browser timeouts;
  • Kernel cleanup in finally.

Threat 7 — Stuck RUNNING job

Risk: Val Town/runtime interruption leaves queue permanently locked.

Controls:

  • 90-second lease;
  • stale lease recovery;
  • retry budget checked during recovery;
  • terminal failure when retry budget exhausted.

Validated with a real stale-job fixture that was removed after testing.

Threat 8 — Cost surprise

Kernel

  • recurring free credits are finite;
  • no automatic runner;
  • short browser timeout;
  • cleanup in finally;
  • actual Kernel GB-second usage remains provider-authoritative.

Browserless

  • local estimate covers base browser-time units only;
  • CAPTCHA/proxy add-ons are not inferred as free;
  • before activation, provider overage spend limit must be set to $0;
  • no automatic browser cron;
  • compare local estimated units to provider accounting.

Threat 9 — False PASS

Controls:

  • TOOL_SUCCESS_RESPONSE != BEHAVIOR_PROOF;
  • no checks -> PARTIAL, not PASS;
  • PASS requires at least one positive expectation and all expectations true;
  • provider/module/pricing availability never promotes a tool to OPERATIONAL;
  • credential, browser creation, actual action, validation and usage evidence are separate states.

Threat 10 — Public Free-tier source exposure

The personal Val Town Free workspace requires public source visibility.

Controls:

  • no secrets in source;
  • public HTTP endpoint exposes liveness only;
  • detailed task/provider state stays behind authenticated plugin execution;
  • env-var values are never returned by normal Val Town listing tools;
  • source assumes it is publicly readable.

Evidence-state vocabulary

  • AVAILABLE: provider/service exists.
  • ADAPTER_LOADED: code imports in Val Town.
  • CONFIGURED: required env-var key exists.
  • AUTHENTICATED: credential proved usable.
  • AUTHORIZED: required action is permitted.
  • EXECUTED: real provider action occurred.
  • VERIFIED: postcondition proved.
  • OPERATIONAL: full required chain is repeatedly or sufficiently evidenced for intended scope.
  • BLOCKED: known prerequisite prevents execution.
  • UNVERIFIED: evidence is absent; not equivalent to failure.

Current Kernel and Browserless live-browser state remains UNVERIFIED because no user-created provider env vars exist yet.