ShellAllowlist

Process-global allowlist for run_shell. The host sets a set of command prefixes (e.g. "pm list packages", "dumpsys battery", "settings get global") at startup; the tool refuses any command whose argv doesn't start with one of them.

Token matching. Each entry is whitespace-tokenized; it matches a request only if its tokens are exactly equal to the request's first N argv entries (N = entry token count). "pm list" matches argv [pm, list, packages] but NOT [pmx, ...], [pm, listx] or [pm, "list packages"]. Entries therefore can't express an argument containing whitespace. Trailing arguments beyond the entry are unrestricted — so allowlist the narrowest prefix that works.

Interpreter entries are rejected. An entry whose first token (or its basename, e.g. /system/bin/sh) is in FORBIDDEN_LEADING_COMMANDS — shells, toybox/busybox, su, app_process, env, xargs, nohup, timeout, etc. — would let any command run as the shell/root UID, defeating the allowlist. set throws IllegalArgumentException for such entries (and for blank entries). Commands that can themselves spawn subprocesses given the right arguments (find -exec, awk 'BEGIN{system(...)}', am-started instrumentation) are not all enumerable — review each entry with that in mind.

Conservative by design: empty allowlist = run_shell is disabled. The LLM cannot extend the allowlist; only host code can.

Not safe for parallel test execution. Tests mutate the global via set(emptySet()) in @BeforeEach/@AfterEach. If JUnit5 parallel test execution is enabled in this module, concurrent tests would race on prefixes. The current build.gradle.kts doesn't enable parallel mode; if you ever do, fence these tests with @Execution(SAME_THREAD) or refactor the allowlist out of process-global state.

Properties

Link copied to clipboard

Leading commands that are refused as allowlist entries because they execute arbitrary other commands (or a script) from their arguments.

Functions

Link copied to clipboard
fun isAllowed(command: String): Boolean

String form: whitespace-tokenizes command and delegates to the argv overload.

True if some entry's tokens equal the first N entries of argv (argv0 is the bin name). Always false for an empty allowlist.

Link copied to clipboard
fun set(allowed: Set<String>)

Replace the allowlist.

Link copied to clipboard