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.