Project 12: Secure Webhook and Termux Bridge
Connect Android automations to remote systems and Termux through signed, replay-resistant, durable, allowlisted contracts without exposing arbitrary URLs, Intents, or shell commands.
Quick Reference
| Attribute | Value |
|---|---|
| Difficulty | Level 3 - Advanced |
| Time Estimate | 24-34 hours |
| Language | Kotlin (alternatives: Java; shell or Python only for a constrained companion prototype) |
| Prerequisites | Projects 3, 4, 5, 7, and 10; HTTPS; JSON canonicalization; WorkManager; Android Keystore; IPC and threat modeling |
| Key Topics | Webhook authentication, authorization, HMAC, replay defense, idempotency, durable delivery, Keystore, explicit Intents, Termux capability contracts |
1. Learning Objectives
By completing this project, you will:
- Separate transport security, message authentication, freshness, authorization, and idempotency into distinct controls.
- Design a canonical signed envelope whose exact bytes are testable across implementations.
- Use Android Keystore-backed key handles and explicit rotation metadata rather than storing raw long-lived secrets in ordinary preferences.
- Persist outbound delivery intent before network execution and classify retryable, permanent, throttled, and ambiguous outcomes.
- Suppress duplicate external effects with a stable idempotency key at the receiver.
- Accept inbound proposals only for enrolled routine IDs and bounded parameter schemas.
- Require local confirmation for sensitive proposals even when signatures are valid.
- Integrate a Termux companion through named operations and typed results rather than shell text.
- Threat-model a compromised relay, stolen device, stale key, malicious plugin, replay attacker, and network observer.
- Produce redacted traces that explain every delivery and proposal without leaking signatures, secrets, or sensitive payloads.
2. Theoretical Foundation
2.1 Core Concepts
TLS protects a connection, not the complete message lifecycle. HTTPS authenticates the server endpoint and encrypts bytes in transit when certificate validation succeeds. It does not by itself tell a delayed worker whether a stored payload was altered, prove to an independent receiver which enrolled device created a message, prevent an authorized relay from replaying an old request, or define what a valid sender may do. Message-level signing, authorization, replay checks, and idempotency remain separate responsibilities.
Authentication is not authorization. A valid HMAC proves that a party holding the shared key produced the canonical message. It does not grant access to every routine or parameter. Authorization answers a narrower question: may this enrolled key propose routine device-report.v1 for this device, with these fields, at this risk level, now? The bridge uses destination and routine registries, per-key scope, schema validation, risk classification, and optional local confirmation.
Canonicalization defines what is signed. Two logically equivalent JSON documents may differ in whitespace, field order, escaping, number representation, or Unicode normalization. Signing “the JSON” without defining exact bytes creates interoperability failures and sometimes verification gaps. A safe envelope fixes protocol version, method or message kind, destination/routine ID, timestamp, nonce, body digest, key ID, and idempotency key. It either signs a rigorously canonical serialization or signs a simple ordered string of already-normalized fields.
Freshness and replay defense have different layers. A timestamp bounds age but requires a clock-skew policy. A nonce detects reuse but requires retained state. An idempotency key identifies one logical requested effect so retries do not duplicate it. The receiver validates the signature, acceptable time window, key status, nonce uniqueness, routine scope, parameter schema, and idempotency record before acknowledging acceptance. Retention windows must be long enough to cover realistic retries.
At-least-once delivery is the honest default. A worker can time out after the receiver commits an effect but before the phone receives the response. Retrying might be necessary, yet the first attempt may already have succeeded. Exactly-once network effects cannot be assumed. The sender persists a stable delivery and idempotency identity; the receiver atomically records acceptance/result against that identity. An ambiguous timeout remains UNKNOWN_ACCEPTANCE until status inquiry or safe retry resolves it.
WorkManager represents durable intent, not an always-on socket. Outbound webhooks are deferrable network work that should survive process death and wait for connectivity. The durable database row is the source of truth; WorkManager is a disposable mechanism reconciled from that intent. Backoff and constraints help, but business retry classification remains in the adapter. A 400 schema rejection is permanent, a 401 may indicate stale enrollment, a 429 follows server guidance, a 500 is usually retryable, and a timeout is ambiguous.
Keystore reduces key extraction but does not solve every secret problem. Android Keystore can hold non-exportable key material or protect keys used by the app. It does not stop an already-compromised authorized process from asking to sign malicious content. Key IDs, purposes, creation time, scope, rotation state, and revocation remain application data. Logs must never include key bytes, Authorization headers, full signatures, or unredacted sensitive bodies.
Termux is a separate application and authority domain. A bridge to Termux is not an excuse to concatenate a string and invoke a shell. The Android side chooses a fixed operation ID such as device-report.v1; the companion validates a small typed request, executes a fixed implementation, bounds time and output, and returns a typed result. Package/signing lineage, explicit Intent targets, caller verification where available, user enrollment, and capability negotiation constrain the relationship. If a supported integration surface is unavailable, the capability is unavailable—not silently replaced with a broad exported receiver.
Inbound command channels are proposal channels. Remote systems can request that an enrolled routine be considered. The phone still evaluates local policy, current capability, freshness, risk, lock state, and confirmation requirements. High-impact operations are denied or require a local user gesture. The project explicitly excludes credential entry, permission grants, purchases, device-admin enrollment, destructive account actions, and arbitrary script execution.
2.2 Why This Matters
Remote triggers make Android automation far more useful: a home server can request a device health report, a phone can publish a charging event, and a Termux tool can perform a local operator-controlled calculation. The same bridge can also become remote code execution, surveillance, or an unbounded data-exfiltration path if authentication is mistaken for authorization.
This project teaches messaging patterns used in payment webhooks, CI agents, IoT command planes, mobile sync, and enterprise integration. Durable intent, idempotent receivers, key lifecycle, narrow schemas, and explicit trust boundaries are reusable production skills.
2.3 Historical Context / Background
Webhooks began as simple HTTP callbacks, often authenticated only by a secret in a URL. Mature providers moved toward signatures over timestamps and payloads, replay windows, key identifiers, and delivery IDs. At the same time, Android background restrictions made embedded always-on servers increasingly unsuitable for ordinary consumer apps. Durable outbound work and push-mediated proposal delivery fit the platform better than exposing a listening port on a mobile network.
Termux provides a Linux-like userspace inside an Android app sandbox. Its APIs and add-ons have installation-source and signing constraints, and Android still treats Termux and FlowForge as separate UIDs. The sound mental model is application-to-application integration, not “the phone has one shared shell.”
2.4 Common Misconceptions
- “HTTPS means I do not need a message signature.” TLS and message provenance solve different problems.
- “A valid signature authorizes any command.” It authenticates a key; allowlists and schemas authorize a specific operation.
- “A random nonce prevents duplicate effects.” Nonces detect replay; stable idempotency identifies a logical effect across retries.
- “WorkManager gives exactly-once execution.” Workers may run more than once and external acceptance can be ambiguous.
- “Keystore makes a compromised app harmless.” Authorized code can still request cryptographic operations.
- “An embedded phone server is the easiest inbound path.” Mobile addressing, exposure, lifecycle, TLS, and authentication make it risky.
- “Termux integration requires arbitrary shell commands.” Named capability adapters are safer and easier to evolve.
- “Retry every non-200 response.” Permanent client errors and revoked enrollment require different handling.
3. Project Specification
3.1 What You Will Build
Build three cooperating lab components:
- Android outbound delivery adapter: Converts selected redacted automation events into durable, signed webhook deliveries to an enrolled destination.
- Controlled test relay: Verifies signatures, freshness, nonce, and idempotency; records one logical effect; and can emit signed routine proposals back through a test transport.
- Termux companion adapter: Advertises a small versioned capability catalog and accepts only named operations such as
device-report.v1orhash-file.v1with bounded parameters.
The Android UI contains Destination Enrollment, Delivery Timeline, Inbound Proposals, Companion Capabilities, and Key Rotation screens. It never provides free-form URL execution or a remote shell text box.
3.2 Functional Requirements
- Destination enrollment: Store a named destination, pinned HTTPS origin policy, key ID, scope, and enabled event types.
- Canonical envelope: Define protocol version, timestamp, nonce, body digest, delivery ID, idempotency key, and signature input.
- Keystore lifecycle: Create, activate, rotate, retire, and revoke keys without exporting them into logs or backups.
- Durable outbox: Commit delivery intent and immutable payload digest before scheduling network work.
- Retry classifier: Handle success, client rejection, auth failure, throttling, server failure, TLS failure, and timeout distinctly.
- Receiver idempotency: Repeated delivery IDs produce one accepted logical effect and the same stable status.
- Inbound verification: Validate signer, freshness, nonce, routine scope, device binding, and schema before planning.
- Risk gate: Execute only low-risk preapproved routines; hold medium-risk proposals for local confirmation; deny prohibited actions.
- Termux catalog: Negotiate companion version, operation IDs, parameter schemas, deadlines, and maximum result sizes.
- No shell source: Dynamic values never select an executable, path outside allowed roots, or interpreter text.
- Bounded results: Large companion output is stored privately and represented by an opaque local reference.
- Redacted observability: Trace hashes, IDs, attempt class, and timing without secrets or raw sensitive bodies.
3.3 Non-Functional Requirements
- Security: Default deny, explicit enrollment, least authority, constant-time signature comparison, and secure network configuration.
- Reliability: Outbound intent survives process death and network outage; retries do not duplicate effects.
- Privacy: Destination receives only fields declared for the enrolled event type.
- Performance: Payload and response bounds prevent memory or database amplification.
- Usability: The UI explains queued, accepted, rejected, retrying, confirmation-required, and ambiguous states.
- Compatibility: Termux absence, incompatible signing source, missing companion, or version mismatch appears as capability state.
- Policy: No downloaded executable code, hidden command channel, security-setting automation, or deceptive background behavior.
3.4 Example Usage / Output
Delivery 01K0-OUT-042
Destination: Home Relay (enrolled)
Event type: device.power.connected.v1
Key ID: phone-key-2026-02
Body: sha256:8b1d...f930
Idempotency: evt-01K0-POWER-998
Attempt 1: TIMEOUT / acceptance unknown
Attempt 2: 200 / duplicate recognized
Logical effect: ACCEPTED ONCE
Next retry: none
Inbound proposal 01K0-IN-077
Signer: Home Relay key relay-2026-03
Routine: device-report.v1
Freshness: 4s
Replay check: NEW
Authorization: ALLOWED_LOW_RISK
Result: COMPLETED / typed result stored locally
3.5 Real World Outcome
Enroll a local HTTPS test relay with a displayed key fingerprint and a narrow list of event types. Trigger a charging event. The Delivery Timeline immediately shows a durable queued record, then signature metadata, attempt count, and receiver result. Disconnect the network before a second event; the record remains queued without a busy loop. Restore the network and observe one receiver effect.
Run the ambiguity test: configure the relay to accept and commit a delivery but delay its response until the phone times out. The phone marks acceptance unknown and retries with the same idempotency key. The relay reports the duplicate and returns the original result, proving one logical effect.
Send four inbound proposals: a valid low-risk device report, a medium-risk routine requiring local confirmation, an expired request, and an unknown operation containing shell metacharacters. Only the valid report runs automatically; the second waits behind a clear notification; the latter two are rejected before planning.
Finally, enroll the Termux companion. The capability screen shows supported operation IDs and version. Invoke device-report.v1 and receive a bounded typed result. Attempts to send arbitrary shell text, dynamic executable names, or out-of-root paths fail schema validation and never reach an interpreter.
4. Solution Architecture
4.1 High-Level Design
normalized event
|
v
+----------------------+ DB transaction +------------------+
| Outbound Projector | ----------------------> | Durable Outbox |
| allowlisted fields | | payload + IDs |
+----------------------+ +--------+---------+
|
WorkManager signal
|
v
+--------------------------+
| Delivery Adapter |
| canonicalize -> sign |
| HTTPS -> classify result |
+------------+-------------+
|
v
+--------------------------+
| Controlled Relay |
| verify -> replay -> auth |
| idempotent acceptance |
+--------------------------+
signed proposal explicit local integration
| |
v v
+----------------------+ pure policy plan +------------------------+
| Inbound Verifier | ------------------------> | Routine Registry |
| signer/time/nonce | | risk + schema + scope |
+----------------------+ +-----------+------------+
|
+------------------+------------------+
| |
v v
Android action adapter Termux companion port
named operation only
4.2 Key Components
| Component | Responsibility | Key Decisions |
|---|---|---|
| Destination registry | Stores approved origins, event scopes, and key metadata | Rules reference IDs, never arbitrary URLs |
| Payload projector | Selects and redacts fields for each outbound event | Schema-specific allowlist |
| Canonicalizer | Produces exact versioned signature input | Reject non-canonical/unsupported forms |
| Keystore signer | Signs or authenticates without exporting key material | Key handle plus lifecycle metadata |
| Outbox repository | Stores immutable delivery intent and attempts | Database is source of truth |
| Delivery worker | Claims due records and performs bounded HTTPS | Unique claim lease and timeout |
| Retry classifier | Maps responses/errors to next state | Ambiguous acceptance is explicit |
| Inbound verifier | Checks signature, freshness, nonce, device, and key | Verification before parsing into actions |
| Routine registry | Maps fixed IDs to schema, risk, and adapter | Default deny; no free-form execution |
| Confirmation gate | Requires a local gesture for selected risk levels | Proposal expires while waiting |
| Termux capability adapter | Negotiates and invokes fixed companion operations | Explicit target, bounded payload/result |
| Security trace | Persists redacted stage evidence | Never stores secrets/signatures in full |
4.3 Data Structures
DestinationEnrollment
destination_id
origin_policy
active_key_id
allowed_event_types
payload_profiles
state: active | rotating | paused | revoked
SignedEnvelope
protocol_version
message_kind
sender_id
target_id
key_id
timestamp
nonce
idempotency_key
body_digest
body
signature
DeliveryRecord
delivery_id
destination_id
immutable_envelope_digest
state
attempt_count
next_attempt_at
acceptance_state
last_result_class
RoutineDescriptor
routine_id
version
parameter_schema_digest
allowed_signers
risk: low | confirm | denied
required_capabilities
deadline
maximum_result_bytes
4.4 Algorithm Overview
Key Algorithm: Verify, Authorize, and Accept Proposal
- Enforce a small maximum body size before decoding.
- Parse only the envelope header needed to select protocol and key.
- Reject unknown, retired, or wrong-scope key IDs.
- Recompute canonical bytes and verify the message authentication code using constant-time comparison.
- Check device binding, timestamp window, and nonce uniqueness.
- Look up the fixed routine descriptor and validate bounded parameters.
- Apply signer scope and local risk policy.
- Atomically record nonce/idempotency acceptance and proposed operation.
- Return
ACCEPTED,CONFIRMATION_REQUIRED,DUPLICATE, or a stable rejection code. - Execute later through the selected adapter and persist the outcome.
Complexity Analysis:
- Signature verification and body hashing are O(payload bytes).
- Routine and key lookup are O(1) with indexed identifiers.
- Nonce/idempotency checks are O(log N) in a database index or expected O(1) in a keyed store.
- Storage is O(retained deliveries + replay records), bounded by explicit retention.
5. Implementation Guide
5.1 Development Environment Setup
Use Android Studio, an emulator or test phone, a locally controlled HTTPS relay, and Termux only on a device where you can verify its installation source and companion contract. Generate lab keys specifically for this project; do not reuse production credentials.
Preflight evidence
- Android API and target SDK recorded
- Network Security Configuration reviewed
- relay certificate and hostname verified
- lab destination fingerprint recorded out of band
- WorkManager test driver available
- Termux track/source/version recorded
- no production URL, key, or token in fixture files
The relay may be implemented separately, but its guide should expose only protocol behavior and test transcripts—not a complete deployable server in this learning file.
5.2 Project Structure
secure-bridge/
|-- domain/
| |-- envelopes/ # canonical models and verification policy
| |-- deliveries/ # durable state machine
| |-- routines/ # allowlisted descriptors and risk
| `-- results/ # typed outcome classes
|-- android-app/
| |-- enrollment/
| |-- keystore/
| |-- outbox/
| |-- inbound/
| |-- confirmation/
| |-- termux/
| `-- diagnostics/
|-- relay-contract/
| |-- protocol.md
| `-- conformance-vectors/
`-- tests/
|-- canonicalization/
|-- security/
|-- worker/
`-- device/
5.3 The Core Question You’re Answering
“How can the phone participate in a larger automation system without turning a stolen key, compromised relay, malicious plugin, or server bug into unrestricted device control?”
Your answer must be expressed as a bounded blast radius. List exactly what each enrolled identity can propose, which data it can receive, what requires local confirmation, and what is impossible by design.
5.4 Concepts You Must Understand First
- Authentication and authorization
- Which property does HMAC prove?
- Where are key scope, routine scope, and risk enforced?
- Book Reference: “Security in Computing” — authentication and access control.
- Canonical signing
- Which exact bytes are signed across Kotlin and the relay?
- How are Unicode, field order, timestamps, and body digests represented?
- Idempotent receiver
- What survives a sender timeout after receiver commit?
- Book Reference: “Enterprise Integration Patterns” — Idempotent Receiver and Correlation Identifier.
- Durable Android work
- Why is the outbox row authoritative instead of the WorkManager request?
- Reference: Android persistent work documentation.
- Key lifecycle
- How are creation, activation, rotation overlap, retirement, and revocation represented?
- Reference: Android Keystore documentation.
- Inter-app trust
- How do explicit targets, exported state, signature identity, and schema version constrain a companion?
- Reference: Android intent-redirection and exported-component security guidance.
5.5 Questions to Guide Your Design
- Can two implementations produce the same canonical test vector byte-for-byte?
- Does the signature bind method/message kind, target, timestamp, nonce, and body digest?
- How much clock skew is allowed, and what does the UI say when a clock is wrong?
- How long are nonce and idempotency records retained?
- Which HTTP outcomes are permanent, retryable, throttled, authentication-related, or ambiguous?
- Can a destination URL be changed by a rule or incoming message?
- Which routine parameters are enumerations, bounded numbers, or private references?
- What happens if confirmation is still pending when a proposal expires?
- Can the Termux result exceed Binder or database limits?
- How does rotation work while old and new keys overlap?
- What evidence remains useful after every secret and sensitive value is removed?
- What can a fully compromised relay still not do?
5.6 Thinking Exercise
Compromised Relay Blast-Radius Table
Assume the relay possesses a currently valid inbound signing key. Build a table for every routine with parameter bounds, data visibility, required phone state, confirmation rule, rate limit, expiration, and adapter authority.
Then attempt these attacks on paper:
- Replay yesterday’s valid report request.
- Change the body while preserving the old signature.
- Replace
device-report.v1withshell.v1. - Put shell metacharacters in a filename parameter.
- Flood ten thousand fresh signed proposals.
- Use a valid key assigned to a different device.
- Ask for a report containing notification text that the routine schema never exposes.
- Rotate keys while one old delivery remains queued.
For each attempt, identify the first boundary that rejects or bounds it. If the answer is “the adapter will probably handle it,” strengthen the earlier contract.
5.7 The Interview Questions They’ll Ask
- “What does HMAC authenticate, and what does it not authorize?”
- “How would you canonicalize and sign a webhook request?”
- “Why do you need both nonce replay defense and an idempotency key?”
- “How do you classify timeout after a receiver may have committed?”
- “How does WorkManager behave under process death and duplicate execution?”
- “How would you rotate keys without dropping queued deliveries?”
- “Why is an inbound HTTP server on a phone usually a poor consumer-app design?”
- “How do you integrate Termux without creating arbitrary remote code execution?”
- “What Android component-export mistakes would threaten this bridge?”
- “What should be redacted from a webhook diagnostic trace?”
5.8 Hints in Layers
Hint 1: Make IDs references to enrollment
Rules store destination and routine IDs. Only a local enrollment flow can assign an origin, key, event scope, or companion target.
Hint 2: Publish conformance vectors
Create nonsecret examples containing input fields, exact canonical bytes, body digest, and expected signature. Both sides must pass them.
Hint 3: Record before scheduling
Persist immutable intent first. Scheduling can be retried or reconciled from database state.
Hint 4: Split acceptance from completion
The receiver can acknowledge durable acceptance with an operation ID before long work finishes. Query result status separately.
Hint 5: Treat the companion as unavailable by default
Require explicit enrollment and capability negotiation. Never discover a broad receiver and assume it is trusted.
5.9 Books That Will Help
| Topic | Book | Chapter/Section |
|---|---|---|
| Messaging contracts | “Enterprise Integration Patterns” | Message, Correlation Identifier, Idempotent Receiver, Request-Reply |
| Authentication and authorization | “Security in Computing” | Authentication, access control, and audit |
| Key and privacy risk | “Foundations of Information Security” | Cryptography, access control, and risk |
| Network failure | “Release It!, 2nd Edition” | Timeouts, stability, and recovery |
| Boundary design | “Clean Architecture” | Component boundaries and external interfaces |
5.10 Implementation Phases
Phase 1: Protocol and Enrollment Foundation (7-9 hours)
Goals:
- Define exact protocol bytes, identities, scope, and key lifecycle.
- Enroll one lab destination without sending business data.
Tasks:
- Write the threat model and prohibited-operation list.
- Define envelope and canonicalization versions.
- Build cross-side conformance vectors.
- Model key states and create a Keystore-backed lab key.
- Add destination enrollment, fingerprint confirmation, and pause/revoke controls.
Checkpoint: Modified body, wrong target, stale timestamp, repeated nonce, wrong key, and unknown protocol vectors all fail with stable reasons.
Phase 2: Durable Outbound Webhooks (8-11 hours)
Goals:
- Deliver allowlisted event projections through a durable outbox.
- Resolve retries and ambiguity without duplicate effects.
Tasks:
- Add schema-specific payload projection and redaction.
- Commit outbox rows before scheduling.
- Implement bounded HTTPS and retry classification.
- Build the receiver idempotency contract.
- Add offline, throttling, server error, and acceptance-timeout scenarios.
Checkpoint: One event accepted before a forced timeout produces one logical receiver effect after retry.
Phase 3: Inbound Proposals and Termux Companion (9-14 hours)
Goals:
- Verify and authorize bounded remote proposals.
- Invoke named Termux capabilities without shell source.
Tasks:
- Build the routine registry and risk/confirmation policy.
- Add atomic replay/idempotency acceptance.
- Implement expiration and confirmation UI.
- Define the companion catalog and typed request/result contract.
- Add explicit targeting and incompatible-version behavior.
- Complete attack, rotation, process-death, and redaction tests.
Checkpoint: Valid report, confirmation-required routine, replay, unknown routine, hostile string, absent companion, and oversized result each produce the designed outcome.
5.11 Key Implementation Decisions
| Decision | Options | Recommendation | Rationale |
|---|---|---|---|
| Inbound transport | Embedded server, push proposal, polling | Push-mediated proposal or bounded polling | Avoids exposing a mobile listener |
| Authentication | URL secret, bearer only, message HMAC | Versioned message authentication over canonical bytes | Binds content and supports independent verification |
| Authorization | Any signed command, role string, routine registry | Per-key routine registry plus parameter schema | Produces a reviewable blast radius |
| Retry truth | Worker state, response code only, durable outbox | Durable outbox plus receiver idempotency | Survives process/network ambiguity |
| Termux request | Shell string, script path, operation descriptor | Fixed operation descriptor | Prevents injection and dynamic execution |
| Sensitive action | Remote auto-run, local confirmation, deny | Confirm or deny by risk | Preserves user control |
| Key rotation | Replace immediately, overlap forever, bounded overlap | Bounded active/retiring overlap | Lets queued work finish without indefinite trust |
6. Testing Strategy
6.1 Test Categories
| Category | Purpose | Examples |
|---|---|---|
| Protocol conformance | Prove cross-language byte identity | Unicode, field order, empty body, maximum values |
| Security | Reject tampering and excess authority | Wrong key, stale request, nonce replay, unknown routine |
| Durable worker | Exercise retry and process death | Offline queue, kill after claim, reschedule |
| Receiver integration | Prove idempotent effects | Accept-then-timeout, duplicate, status query |
| IPC/companion | Bound inter-app behavior | Wrong signer/source, old version, hostile parameters |
| Privacy | Prevent secret leakage | Seeded tokens in body, headers, logcat, export |
| Compatibility | Record Android and Termux variants | API levels, absent add-on, track/signing mismatch |
6.2 Critical Test Cases
- Canonical match: Kotlin and relay produce identical bytes and signature for every vector.
- Payload tamper: One changed byte invalidates the signature.
- Target substitution: Valid message for Device A fails on Device B.
- Stale timestamp: Expired proposal is rejected before routine lookup.
- Nonce replay: Same nonce is rejected within retention.
- Idempotent retry: Same logical delivery produces one effect and stable result.
- Acceptance ambiguity: Timeout after commit resolves through duplicate/status behavior.
- HTTP classification: 400, 401, 409, 429, 500, TLS failure, and timeout reach distinct states.
- Rotation overlap: Old queued delivery and new proposals obey intended key states.
- Unknown routine: Signed but unauthorized ID is denied.
- Hostile parameter: Quotes, separators, newlines, Unicode, and traversal remain inert or fail schema.
- Confirmation expiry: Expired proposal cannot run after a late tap.
- Companion mismatch: Unsupported protocol version produces capability unavailable.
- Oversized output: Companion returns a bounded reference or typed failure, not a Binder crash.
- Seeded secret: No key, signature, token, or private body appears in diagnostics.
6.3 Test Data
Vector ID: canonical-v1-unicode
protocol: bridge.v1
sender: phone-lab-01
target: relay-lab-01
key_id: key-lab-a
timestamp: 2026-07-15T15:04:05Z
nonce: nonce-000042
idempotency_key: event-000099
body classification: synthetic/non-sensitive
expected: both implementations agree byte-for-byte
Attack corpus:
- body modified after signing
- timestamp beyond past/future skew
- duplicate nonce with new delivery ID
- same idempotency key after simulated timeout
- routine="shell.v1"
- filename="../../private; reboot"
- result larger than contract limit
- signature and token seeds that must never export
7. Common Pitfalls & Debugging
7.1 Frequent Mistakes
| Pitfall | Symptom | Solution |
|---|---|---|
| Signing parsed JSON | Valid requests fail across implementations | Specify and test exact canonical bytes |
| Signature equals permission | Signed unknown routine executes | Enforce per-key routine and parameter authorization |
| New ID per retry | Receiver repeats external effect | Keep stable logical idempotency across attempts |
| Retrying all errors | Permanent rejection loops and drains battery | Classify by protocol and transport semantics |
| Logging headers | Secrets appear in logcat/support bundle | Structured redaction before persistence |
| Key replacement without overlap plan | Queued messages become unverifiable | Model active, retiring, retired, revoked states |
| Shell concatenation | Hostile parameter changes execution | Fixed operation IDs and typed values only |
| Broad exported receiver | Other apps invoke internal commands | Explicit targets, least export, and caller/enrollment checks |
7.2 Debugging Strategies
- Canonical-byte viewer: In a safe lab build, show escaped canonical fields and digest—not the secret.
- Stage trace: Separate DNS/TLS/connect/write/read, signature, freshness, replay, authorization, acceptance, and completion.
- Outbox inspector: Show immutable delivery ID, claim lease, attempts, next retry, and ambiguity state.
- Receiver ledger: Query idempotency identity and original acceptance without repeating effects.
- Capability doctor: Report companion package/version/source/operation catalog without invoking it.
- Clock diagnostics: Display sender/receiver difference when freshness fails.
7.3 Performance Traps
Do not wake the radio for every noisy event. Coalesce before creating a delivery where semantics permit, use network constraints, batch low-priority telemetry, and cap attempts. Hash payloads once after immutable projection. Bound request/response bodies before allocation. Prune nonce and idempotency records according to documented windows, but never earlier than valid retry duration. Avoid keeping a long-lived socket solely to simulate an always-on automation server.
8. Extensions & Challenges
8.1 Beginner Extensions
- Add a destination pause control that preserves queued records without sending.
- Add a delivery-reason explainer for each retry class.
- Add a routine catalog screen that shows parameters and risk before enrollment.
8.2 Intermediate Extensions
- Add asymmetric device signatures and compare operational trade-offs with HMAC.
- Add per-destination rate and daily data budgets.
- Add a two-person approval simulation for one managed-device routine.
8.3 Advanced Extensions
- Design a transparency log for enrollment and key changes.
- Add remote attestation only after documenting what it proves and what it does not.
- Formalize the protocol in a language-neutral schema and run property-based conformance tests.
- Build a managed-enterprise variant with organization-issued identities and explicit deprovisioning.
9. Real-World Connections
9.1 Industry Applications
- Payment/provider webhooks: Signed callbacks, replay windows, and idempotent receivers.
- IoT command planes: Device identity, narrow commands, offline queues, and key rotation.
- CI runners: Authenticated jobs constrained to a declared capability catalog.
- Mobile sync: Durable outboxes and process-death-safe delivery.
- Home automation: Local proposals without arbitrary remote shell authority.
9.2 Related Open Source Projects
- Termux app: https://github.com/termux/termux-app - Source and integration context for the companion environment.
- Termux API: https://github.com/termux/termux-api - Example of explicit Android-to-Termux capability surfaces.
- OWASP MASVS: https://github.com/OWASP/owasp-masvs - Mobile security verification requirements and test vocabulary.
- Google Tink: https://github.com/tink-crypto/tink - High-level cryptographic primitives; still requires protocol and key-lifecycle design.
9.3 Interview Relevance
- Security design: authentication, authorization, replay, least privilege, and key rotation.
- Distributed systems: at-least-once delivery, ambiguity, idempotency, and durable outbox.
- Android: WorkManager, Keystore, component export, explicit Intents, and process death.
- API design: versioned envelopes, schemas, error taxonomy, and compatibility.
- Operations: redacted traces, status inquiry, and recovery after network failure.
10. Resources
10.1 Essential Reading
- Persistent work: https://developer.android.com/develop/background-work/background-tasks/persistent - Choosing and operating WorkManager-backed work.
- WorkManager guide: https://developer.android.com/develop/background-work/background-tasks/persistent/getting-started - Current scheduling and worker concepts.
- Android Keystore: https://developer.android.com/privacy-and-security/keystore - Key storage and cryptographic-operation guidance.
- Network Security Configuration: https://developer.android.com/privacy-and-security/security-config - Declarative trust configuration and cleartext controls.
- Intent redirection risk: https://developer.android.com/privacy-and-security/risks/intent-redirection - Safer component and Intent handling.
- Google Play Device and Network Abuse policy: https://support.google.com/googleplay/android-developer/answer/9888379 - Distribution constraints relevant to remote control and downloaded code.
10.2 Video Resources
- Android Developers background-work sessions: https://www.youtube.com/@AndroidDevelopers - Use current official WorkManager and app-security talks.
- OWASP Mobile Application Security project: https://mas.owasp.org/ - Talks and testing resources linked from the project.
10.3 Tools & Documentation
- WorkManager testing: https://developer.android.com/develop/background-work/background-tasks/testing/persistent
- Security best practices: https://developer.android.com/privacy-and-security/security-best-practices
- Cryptography guidance: https://developer.android.com/privacy-and-security/cryptography
- Package visibility: https://developer.android.com/training/package-visibility
- Termux:Tasker repository: https://github.com/termux/termux-tasker
- OWASP MASVS network controls: https://mas.owasp.org/MASVS/08-MASVS-NETWORK/
- OWASP MASVS storage controls: https://mas.owasp.org/MASVS/06-MASVS-STORAGE/
- Google Play User Data policy: https://support.google.com/googleplay/android-developer/answer/10144311
10.4 Related Projects in This Series
- Project 4: Durable Automation Library supplies durable rule and migration state.
- Project 5: Timekeeper Scheduler supplies constraint-aware persistent work.
- Project 7: Command Surface Deck establishes user-visible invocation surfaces.
- Project 10: Plugin SDK and IPC Host supplies versioning and caller-trust patterns.
- Project 14: Automation Observatory adds ambiguity fault injection and secret-safe support bundles.
- Project 15: FlowForge Automation Studio integrates enrolled destinations and companions.
11. Self-Assessment Checklist
Before considering this project complete, verify:
11.1 Understanding
- I can distinguish TLS, message authentication, authorization, freshness, replay defense, and idempotency.
- I can define the exact canonical bytes for protocol version 1.
- I can explain ambiguous acceptance after a timeout.
- I can describe every key lifecycle state and transition.
- I can state the maximum authority of each inbound signer.
- I can explain why the Termux adapter never accepts shell text.
11.2 Implementation
- All functional requirements are met with bounded payloads and results.
- Conformance vectors pass across the Android and relay sides.
- Offline and process-death scenarios preserve the outbox.
- Receiver retries produce one logical effect.
- Inbound replay, stale, wrong-target, and unknown-routine tests fail safely.
- Key rotation and revocation tests pass.
- No fixture secret appears in logs, history, or support exports.
11.3 Growth
- I documented one place where authentication had initially been confused with authorization.
- I can defend replay and idempotency retention windows.
- I can explain the bridge in a distributed-systems and mobile-security interview.
- I can identify what would require a separate enterprise or sideload distribution track.
12. Submission / Completion Criteria
Minimum Viable Completion:
- One enrolled HTTPS destination with canonical signed outbound delivery.
- Durable offline queue and typed retry classification.
- Idempotent receiver behavior for a simulated accept-then-timeout.
- Inbound allowlisted low-risk routine with freshness and replay checks.
- A Termux named-operation contract that rejects arbitrary shell text.
Full Completion:
- All minimum criteria plus local confirmation, key rotation, redacted traces, protocol conformance vectors, process-death tests, and companion capability negotiation.
- A threat model covering compromised relay, stolen phone, leaked key, malicious app, replay, and denial-of-service.
- A documented policy matrix for consumer, managed, and developer-only distribution.
Excellence (Going Above & Beyond):
- A property-based protocol conformance suite with malformed and adversarial envelopes.
- A quantitative retry/battery study under offline, throttled, and flaky-network profiles.
- A reviewed blast-radius document proving what a valid but compromised signer cannot do.
This guide was generated from ANDROID_AUTOMATION_APPS_MASTERY.md. For the complete learning path, see the expanded project index.