tapp@0.35.5
CAUTION· startup onlyPublisher claims: "Let coding agents verify UI changes on real iOS, Android, and web surfaces, then enforce reviewed proof in deterministic CI." Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Startup only; authenticated tool behavior not tested.- Tested
- server startup over stdio (initialize sent) · every file read, file written and host contacted by what ran
- Not tested
- the tool list (the server exited before answering) · what the tools do when called with real credentials
What this means for the label: Caution here covers what ran. The server's tools were not exercised with a real credential, so nothing about their behavior is asserted; the credential summary below says what to do with that.
Before you give it your token
- It will ask for
ANTHROPIC_API_KEYOCQA_CREDENTIALS_EXPLICITOCQA_TEST_PASSWORDTAPP_MCP_TOKENTAPP_SUBSCRIPTION_TOKENTAPP_TOKENTEST_PASSWORDConfiguration, not credentials: ANDROID_HOME, ANDROID_SDK_ROOT, APK_PATH, APP_PATH, FLOW_LOG, GITHUB_SHA, GITHUB_STEP_SUMMARY, OCQA_APP_LAUNCH_ARGS_JSON, OCQA_APP_LAUNCH_ENV_JSON, OCQA_INPUT_OVERRIDES_JSON, OCQA_INPUT_RESPONSE_PATH, OCQA_INTERACTIVE_INPUT, OCQA_LOGIN_STEPS_JSON, OCQA_PR_TARGET_JSON, OCQA_RECORDING_STARTED_PATH, OCQA_SESSION_CMD_PATH, OCQA_SESSION_RESULT_PATH, OCQA_TEST_EMAIL, OCQA_VISUAL_READY_PATH, PR_PLAN_PATH, PR_SELECTION_PATH, PR_TARGET_PATH, RECORDING_STARTED_PATH, TAPP_ACCESS_AUD, TAPP_ACCESS_TEAM_DOMAIN, TAPP_ADMIN_EMAILS, TAPP_BROWSER_PROXY_SERVER, TAPP_ENABLE_REMOTE_AI, TAPP_ENFORCE_PUBLIC_EGRESS, TAPP_FINDING_MODEL, TAPP_FLOW_CONTINUE, TAPP_FLOW_EVIDENCE_DIR, TAPP_FLOW_EVIDENCE_DIR_RESOLVED- Where it talks to
- runtapp.com (its own)Also example.test, your.domain, slack.com, resend.com, google.com, tapp.invalid — not the publisher's domain; check what for before connecting.
- What the honeypot saw
- no credential files read · no network
- What we could not test
- the tool list (the server exited before answering) · what the tools do when called with real credentials
Connect it with a scoped credential, under the guard, and read the third-party hosts first. The code names example.test, your.domain, slack.com, resend.com, google.com, tapp.invalid as well as its own vendor. The guard injects ANTHROPIC_API_KEY, OCQA_CREDENTIALS_EXPLICIT, OCQA_TEST_PASSWORD, TAPP_MCP_TOKEN, TAPP_SUBSCRIPTION_TOKEN, TAPP_TOKEN, TEST_PASSWORD only into requests to runtapp.com (and its subdomains) and refuses the rest.
Never paste a credential into a chat, a ticket or a report, including ours. How the guard holds it.
Is [email protected] safe to install?
KillerSkills ran it in the KillerSkills honeypot sandbox (2 scenarios; startup only; authenticated tool behavior not tested) on 2026-11-09 and scored it 62/100 (Caution). It is not known to be malicious, but it has behaviour or code a security policy should decide on before install. Notable findings: Image alt text carrying instructions; Access to sensitive file paths; Access to sensitive file paths. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 28 s · 2 scenarios · 0 deviationsStatic findings
console.error("Run `npx -y @aarwitz/tapp@latest --help` for the command reference.");Fix: Pin versions and sources; vendor anything fetched at install time.npx -y @aarwitz/tapp@latest look [target] # launch + screen summary + screenshot saved to a file (≈ tapp_look)Fix: Pin versions and sources; vendor anything fetched at install time.A real Tapp focus run reaches Update Profile from source and an observed routeFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.if (record?.credentials?.password) variables.TEST_PASSWORD = record.credentials.password;Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.npx -y @aarwitz/tapp@latest explore [target] # autonomous exploration → findings + evidence (observation, not a gate; ≈ tapp_explore)Fix: Pin versions and sources; vendor anything fetched at install time.console.log(`\nNext: npx -y @aarwitz/tapp@latest explore ${inst.bundleId}`);Fix: Pin versions and sources; vendor anything fetched at install time.const proc = spawn("bash", cmdArgs, { cwd: repoRoot, env: { ...process.env, ...simEnv(), ...env } });Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.// SIGNED OUT and type the credentials. Handing it a saved sessionFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.storedEmail = record?.credentials?.email || "";Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.console.error("\nℹ️ Tapp located the source but did not drive an unobserved route. Ground the UI Map with `npx -y @aarwitz/tapp@latest init . --explore`.");Fix: Pin versions and sources; vendor anything fetched at install time.storedPassword = record?.credentials?.password || "";Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.errors.push(`actor '${name}'.credentials must be an object of environment bindings`);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.if (record?.credentials?.email) variables.TEST_EMAIL = record.credentials.email;Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.return { actor, hasCredentials: !!record?.credentials, hasSession: !!record?.session, sessionSavedAt: record?.sessionSavedAt || null };Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.console.error(`❌ ${what} requires macOS (Xcode + iOS simulator). Web runs anywhere: npx -y @aarwitz/tapp@latest explore https://localhost:3000`);Fix: Pin versions and sources; vendor anything fetched at install time.const binding = configured.credentials?.[key]?.env;Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…t = 0, launch = false, workspaceRoot, githubProvider, publicOrigin = "", trustedProxyToken = "", directLogin = null, publicEgressOnly = null, publicAccess = false, access…Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const proxyAuthenticated = !!trustedProxyToken && sameSecret(request.headers["x-tapp-proxy-token"], trustedProxyToken);Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.const hosted = !!trustedProxyToken || !!directLogin || !!publicAccess;Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.npx -y @aarwitz/tapp@latest explore --read-only https://example.com --pages 5 # never clicks: production or a site you do not ownFix: Pin versions and sources; vendor anything fetched at install time.if (definition.secret && (["email", "password"].includes(name) || configuredActors[actorName]?.credentials?.[name]?.env)) return [];Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.npx -y @aarwitz/tapp@latest explore https://your-app.example --watch # web: visibly follow the same explorationFix: Pin versions and sources; vendor anything fetched at install time.npx -y @aarwitz/tapp@latest explore --goal "SCREEN OR CONTROL" [target] # source-locate + shortest observed route + screenshotFix: Pin versions and sources; vendor anything fetched at install time.lines.push(" sudo chmod 666 /dev/kvm");Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.// "new visitors", 383 of which were bots probing for .env files, which is a readingFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.…erts-form" class="signin-row"><input id="alert-webhook" type="url" placeholder="https://hooks.slack.com/services/…" required><button class="primary" type="submit">Save</button></form><…Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.console.log(` plan: ${adopted.path}\n next: npx -y @aarwitz/tapp@latest plan review ${adopted.path} --approve ${adopted.item.id}`);Fix: Pin versions and sources; vendor anything fetched at install time.lines.push(" sudo chmod 666 /dev/kvm");Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.[ -n "$RESPONDER_PID" ] && { kill "$RESPONDER_PID" 2>/dev/null; wait "$RESPONDER_PID" 2>/dev/null; }Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.message: `A folder on your machine is not visible from the cloud. Open it with the Studio there: npx -y @aarwitz/tapp@latest app ${prompt.value}` });Fix: Pin versions and sources; vendor anything fetched at install time.…push(`Gradle wrapper is missing from ${androidProject}; commit gradlew or rerun npx -y @aarwitz/tapp@latest init from the Gradle repository root`); inputs["androi…Fix: Pin versions and sources; vendor anything fetched at install time.…und credential requirements: ${missingBindings.join(", ")}.`, remediation: `Run npx -y @aarwitz/tapp@latest actor set ${actor.name} --credential <name>=<ENV_NAME> for…Fix: Pin versions and sources; vendor anything fetched at install time.json(response, 401, { error: "That part of the Studio runs on your own machine: npx -y @aarwitz/tapp@latest app" });Fix: Pin versions and sources; vendor anything fetched at install time.…lines.push(` - Reviewable coverage proposal ready; never auto-applied. Next: \`npx -y @aarwitz/tapp@latest pr adopt <pr-plan.json> --item ${target.id} --project-dir …Fix: Pin versions and sources; vendor anything fetched at install time.next.push("replay a committed journey with `npx -y @aarwitz/tapp@latest run <file>`");Fix: Pin versions and sources; vendor anything fetched at install time.// npx installs Tapp into its own cache, so a plain import("playwright") only resolvesFix: Pin versions and sources; vendor anything fetched at install time.screenshots inline. Otherwise run `npx -y @aarwitz/tapp@latest` from the app repository. Do not require MCP,Fix: Pin versions and sources; vendor anything fetched at install time.…a site. iOS, Android and folders on your own machine run the same Studio there: npx -y @aarwitz/tapp@latest app"; $("#actors-panel")?.classList.toggle("hidden", !si…Fix: Pin versions and sources; vendor anything fetched at install time.while kill -0 "$HARNESS_PID" 2>/dev/null; doFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.if [[ -z "$RECORD_PID" ]] || ! kill -0 "$RECORD_PID" 2>/dev/null; thenFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.if ! kill -0 "$PREFLIGHT_PID" 2>/dev/null; then PREFLIGHT_CRASH=1; fiFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.json(response, 400, { error: `This Studio cannot reach ${target.hostname} — it only opens public addresses. Run tapp where that app is: npx -y @aarwitz/tapp@latest app` });Fix: Pin versions and sources; vendor anything fetched at install time.1. If `.tapp/application-model.json` exists, run `npx -y @aarwitz/tapp@latest explore`.Fix: Pin versions and sources; vendor anything fetched at install time.if (!fs.existsSync(targetPath)) throw new Error(`Release plan not found: ${targetPath}; run npx -y @aarwitz/tapp@latest init first`);Fix: Pin versions and sources; vendor anything fetched at install time.…at ${summary.expectedPath || summary.path}.` : "Build/launch the target and run npx -y @aarwitz/tapp@latest init --explore so real exploration evidence is merged into…Fix: Pin versions and sources; vendor anything fetched at install time.…s !== "proposed"); const refreshAdvice = "refresh the persistent UI Map with `npx -y @aarwitz/tapp@latest init --explore --refresh`, rerun `npx -y @aarwitz/tapp@lat…Fix: Pin versions and sources; vendor anything fetched at install time.…emediation: "Add a deterministic start/static target or start the app and rerun npx -y @aarwitz/tapp@latest init with --url http://127.0.0.1:<port>." }); if (targ…Fix: Pin versions and sources; vendor anything fetched at install time.`npx -y @aarwitz/tapp@latest doctor`, apply only the stated remediation that is in scope, andFix: Pin versions and sources; vendor anything fetched at install time.1. In a source repository, run `npx -y @aarwitz/tapp@latest explore --goal "<exact request>" [target]`;Fix: Pin versions and sources; vendor anything fetched at install time.kill -INT $RECORD_PID 2>/dev/null || trueFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.json(response, 200, { kind: "self-host", target: prompt.value, command: "npx -y @aarwitz/tapp@latest app",Fix: Pin versions and sources; vendor anything fetched at install time.json(response, 200, { kind: "self-host", target: prompt.value, command: `npx -y @aarwitz/tapp@latest app ${prompt.value}`,Fix: Pin versions and sources; vendor anything fetched at install time.…message: `Confirm a shared build scheme for ${target.name}.`, remediation: `Run npx -y @aarwitz/tapp@latest build ${target.sourcePath} or provide the scheme during in…Fix: Pin versions and sources; vendor anything fetched at install time.if (!fs.existsSync(modelPath)) return { error:"No application model found — run `npx -y @aarwitz/tapp@latest init . --explore --platform android` first." };Fix: Pin versions and sources; vendor anything fetched at install time.if (model?.kind !== "tapp-application-model" || !Array.isArray(model.targets) || !model.targets.length) throw new Error("Application model has no targets; run npx -y @aarwitz/tapp@latest init first");Fix: Pin versions and sources; vendor anything fetched at install time.2. Otherwise run `npx -y @aarwitz/tapp@latest init . --explore` or call `tapp_init` withFix: Pin versions and sources; vendor anything fetched at install time.export const SELF_HOST_COMMAND = "npx -y @aarwitz/tapp@latest app";Fix: Pin versions and sources; vendor anything fetched at install time.if (report?.findings?.length) next.push("inspect the evidence with `npx -y @aarwitz/tapp@latest report latest`");Fix: Pin versions and sources; vendor anything fetched at install time.… again. iOS, Android and folders on your own machine run the same Studio there: npx -y @aarwitz/tapp@latest app" : "Websites are audited read-only in the cloud; n…Fix: Pin versions and sources; vendor anything fetched at install time.if ! kill -0 "$RECORD_PID" 2>/dev/null; thenFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.console.log(`Listening on ${product.origin} — put a TLS terminator or tunnel in front of it.`);Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.// Playwright is deliberately NOT a required dependency of Tapp (it would bloat every npxFix: Pin versions and sources; vendor anything fetched at install time.choices: apps.map((app) => ({ platform: "ios", name: app.name, bundleId: app.bundleId, selector: app.bundleId, command: `npx -y @aarwitz/tapp@latest tree ${app.bundleId}` })),Fix: Pin versions and sources; vendor anything fetched at install time.…kage-manager lockfile so Tapp can install dependencies reproducibly, then rerun npx -y @aarwitz/tapp@latest init." }); } const incompleteMaps = uiMaps.filter((rec…Fix: Pin versions and sources; vendor anything fetched at install time.throw new Error("Expected a Tapp application model; run npx -y @aarwitz/tapp@latest init first");Fix: Pin versions and sources; vendor anything fetched at install time.lines.push(` - Optional explicit evidence reconciliation: \`npx -y @aarwitz/tapp@latest pr adopt <pr-plan.json> --item ${target.id} --project-dir .\``);Fix: Pin versions and sources; vendor anything fetched at install time.…usage: tapp validate <task.yml> [--platform ios|android|web] [--map .tapp/ui-map.json]\n tapp validate <task.yml> --compile --platform PLATFORM [--inputs '{\"name\":\"value\"}'] [--out compiled.json]\n tapp run <task.yml> --platform PLATFO…Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why.else return { error: "tree inspects an installed app. Pass its bundle id, or run npx -y @aarwitz/tapp@latest build explicitly before inspecting it." };Fix: Pin versions and sources; vendor anything fetched at install time.console.log(` inputs: ${Object.keys(task.inputs || {}).join(", ") || "none"} · outputs: ${Object.keys(task.outputs || {}).join(", ") || "none"}`);Fix: Remove the call, or declare the host in frontmatter and explain in the README what is sent and why."then `npx playwright install chromium`."Fix: Pin versions and sources; vendor anything fetched at install time.…tor credential binding '${name}' is not a safe environment-variable name; rerun npx -y @aarwitz/tapp@latest init from valid .tapp/project.json`); const inputs = {};…Fix: Pin versions and sources; vendor anything fetched at install time.Cost to the agent
Tokens estimated at four characters each. The tool list is re-read by the agent on every turn, so it is the number to compare between servers that do the same job: ranked across the index.
Known vulnerabilities
No advisories in OSV for @aarwitz/tapp@0.35.5 as of 5d ago. This is the package itself, not its dependencies.
What would make this Verified
18 points to 80 · weights: behavior 45%, static 25%, prompt 15%, publisher 15%- Prompting user to enter sensitive credentials≈ +9 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Unclaimed publisher≈ +8 on the totalClaim aarwitz: a verified publisher gets +50 on publisher trust. It is free and usually instant with GitHub sign-in.
- Hidden instructions≈ +6 on the totalRemove HTML comments, zero-width characters and white-on-white text that carry instructions. Everything the agent is meant to read should be visible to the person reading the file.
- Access to sensitive file paths≈ +4 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Credential pass-through configuration≈ +4 on the totalStop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.
- Privileged sudo command≈ +4 on the totalBuild commands from fixed arguments; do not interpolate untrusted strings into a shell.