Skip to content

Explorer: judge a tap by the control under it and by its identifier - #77

Draft
brentvatne wants to merge 1 commit into
mainfrom
@brent/explorer-tap-safety
Draft

brentvatne wants to merge 1 commit into
mainfrom
@brent/explorer-tap-safety

Conversation

@brentvatne

Copy link
Copy Markdown
Member

What and why

Two gaps let a model-driven exploration tap a destructive control.

  • Identifiers were not split. riskOf matched \bdelete\b, which doesn't match btn_delete or deleteAccount: _ is a word character, and camelCase has no boundary. It now splits identifiers into words before matching.
  • A coordinate tap over a control the map hadn't recorded was judged only by the model's own description of it (target), or recorded as unknown and let through. It is now also judged by the smallest hittable control under the point, using that control's label and identifier. A tap over no control is still allowed and recorded as unknown, so unlabelled icon buttons keep working.

A control allowed with --allow-destructive "Label" stays allowed however it is tapped, even when its identifier reads as risky (resetFilters). A refusal now mentions --allow-destructive, for whoever runs Explore: the model can't pass it, but the message reaches people through flow and replay results.

The README and the explore-binary skill now say that a secret is recognised only in the accessibility tree, so a value drawn without an accessible label (in a canvas or an image) gets no such protection.

This comes from comparing Explore's safety rules against what a model can actually send.

Screenshots

No visible change.

Code examples

// src/binary/explorer.ts, riskOf: identifiers join their words, which \b does not split
const words = label.replace(/(\p{Ll}|\d)(\p{Lu})/gu, "$1 $2").replace(/[_.-]+/g, " ");
riskOf("btn_delete", [])        // "destructive" (was "safe")
riskOf("deleteAccount", [])     // "destructive" (was "safe")
riskOf("openInSafari", [])      // "external"
riskOf("postsTab", [])          // "safe"

Try it

npx @expo/explore explore:binary ./MyApp.tar.gz --simulator local

A coordinate tap on an icon button whose identifier is btn_delete is refused, and the attempt is recorded with risk destructive.

Testing

  • New tests in test/node/binary-explorer.test.mjs:
    • joined identifiers are recognised;
    • a coordinate tap is judged by the control under the point, whatever the model calls it;
    • a coordinate tap over no control is still allowed;
    • a control allowed by its label goes through, whether tapped by position or by identifier.
  • Each change was broken on purpose, and a test fails. The exception is the allowance for coordinate taps, which the existing label allowance already covers whenever the map knows the control.
  • npm test passes (1711 tests), tsc is clean, and lint shows only the 6 existing Viewer warnings.

🤖 Generated with Claude Code

…and name --allow-destructive in a refusal

- riskOf splits identifiers into words before matching, so btn_delete, deleteAccount and
  sign-out read as destructive; \b does not split them.
- A coordinate tap is judged by the smallest hittable control under the point, by its own
  label and identifier, as well as by the target the model wrote. A tap over no control is
  still allowed and recorded as unknown.
- A control allowed by its label stays allowed however it is targeted, even when its
  identifier reads as risky.
- A refusal tells whoever runs Explore that --allow-destructive allows a safe control; it
  reaches them through flow and replay results.
- The README and the explore-binary skill say that a secret is recognised in the
  accessibility tree only, so one drawn without an accessible label is not.
@github-actions

Copy link
Copy Markdown

Viewer preview of c919c42 · reports from brentvatne/euxy#163

Report Changes Open
Android · sdk_gphone64_x86_64 15.0 5 Map · Screens · Compare
iPhone 17 · iPhone 17 26.5 · light + dark 11 Map · Screens · Compare
iPhone Duo (closed) · iPhone Duo 27.1 · light + dark 34 Map · Screens · Compare
iPhone Duo (open) · iPhone Duo 27.1 · light + dark 34 Map · Screens · Compare

The link stays the same on every push. Deploy run

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant