DDevineSecurity Engineer

Security simulation — RBAC, dual-control, and tamper-evident logging · Case study

Android Reset Lab

Simulation / lab

Android Reset Lab simulates sensitive device reset workflows with layered security controls. Includes Merkle transparency log with inclusion and consistency proofs, Cedar ABAC policy-as-code, risk-adaptive authentication, WebAuthn passkeys, Play Integrity attestation, transaction signing, and token binding. Test suite covers tamper detection, self-approval blocking, policy enforcement, and attack scenarios. Simulation-only — no real device operations. Serves as reference implementation for Chokepoint's dual-control and audit patterns.

Built with

  • Python + pytest + cryptographic controls
  • Merkle transparency and policy-as-code
  • Risk-adaptive authentication
  • WebAuthn and attestation
  • Security testing and attack simulation

Security concepts

  • Security Simulation
  • RBAC and Dual-Control
  • Tamper-Evident Logging
  • Policy-as-Code
  • Risk-Adaptive Auth
  • Attack Detection

01

Overview

Android Reset Lab simulates the sensitive operation at the heart of enterprise mobile management: wiping a lost or stolen device. In a real environment a single compromised IT account could wipe an entire fleet, so the lab enforces the controls that prevent single-person abuse — authentication, default-deny authorization, four-eyes approval, and a tamper-evident audit trail — then proves them by attacking the system itself.

Simulation-only by design

It never touches a real device, ADB, or MDM APIs, and it never contacts external networks. Device state is a field that flips from active to wiped in a local data file. An AST-based safety test (test_safety.py) bans destructive calls like subprocess and os.remove. The device is the scenario; the security logic is the subject.
Source on GitHub (opens in a new tab)

02

The problem

Device resets are destructive and irreversible. Without guardrails, one set of stolen admin credentials is enough for an attacker to wipe company phones at scale — and to erase the evidence afterwards. The lab targets five concrete abuses: no single person should wipe a device; brute force should be stopped; the audit log should be un-tamperable; after-hours abuse should be flagged; and non-existent devices should be rejected.

03

Architecture & flow

Built with the Python standard library only (plus pytest for tests), with a JSON or SQLite (WAL, ACID) storage backend selected by an environment variable. The pipeline: authenticate → authorize → request → second approver → simulated wipe → hash-chained/HMAC log → detection → dashboard.

RESET REQUEST PIPELINE (SIMULATED)Login + Passkey + TOTPPBKDF2/Argon2id · WebAuthn origin binding · AAGUID allowlistSession token + DPoP128-bit · 30m TTL · CSRF · jkt binding · proof-of-possessionRisk-adaptive scoringvelocity, impossible travel, device trust, time anomaly, escalationDevice attestationPlay Integrity BASIC/DEVICE/STRONG · StrongBox/TEE/Software · trust_scoreCedar ABAC policy checkexplicit deny, default deny, decision logs, bundle SHA, AuthZENRequest resetvalidate fleet + attestation ≠ untrusted + risk <80 + policy allowFour-eyes + TX signingsecond admin · WYSIWYS HMAC + passkey txAuthSimple · 5m expirySIMULATED wipe + Merklestatus active→wiped · Merkle root + inclusion/consistency proofs + Rekor checkpointThreat detection (23 rules)time-windowed + risk factors + attestation + webauthn clone + DPoP + tx tamper

04

Security controls

Merkle Transparency Log RFC6962/9162

Leaf SHA256(0x00||canonical_json), node SHA256(0x01||L||R), inclusion proofs O(log N), consistency proofs, STH HMAC-signed, checkpoint anchoring simulates Sigstore Rekor with rekor_simulated_id.

Cedar ABAC Policy-as-Code

Principal/Action/Resource/Context model, 10 default policies, explicit deny overrides permit, default deny, decision logs with timestamp/version/bundle SHA, AuthZEN-compatible API, safe AST walk (no eval).

Risk-Adaptive Authentication

8 factors: velocity (req/min), failed_auth/10m, time anomaly (8-18 UTC approved), device trust (trusted 0, compromised 50, emulator 40), MFA (passkey -10 bonus), escalation 40, impossible travel 30 if geo change <10m, session age. Score 0-100 → allow/step_up/tx/deny.

WebAuthn Passkeys

FIDO2 phishing-resistant, origin + RP ID validation, AAGUID allowlist via FIDO MDS (YubiKey 5, Titan M, Windows Hello, Touch ID, Pixel 8 StrongBox), challenge 32B CSPRNG, counter clone detection, backup_eligible flag.

Device Attestation

Play Integrity MEETS_BASIC/DEVICE/STRONG + hardware key attestation Software/TEE/StrongBox (Titan M), keybox.xml validation, patch recent check, bootloader locked, trust_score 0-100 with penalties, GrapheneOS fallback without Play Services.

Transaction Signing WYSIWYS

What You See Is What You Sign HMAC-SHA256, PSD2 dynamic linking, FIDO txAuthSimple extension simulation, explicit display confirmation, 5m expiry, prevents confused deputy and tampering.

DPoP Token Binding RFC9449

Demonstrating Proof-of-Possession JWT with htm/htu/iat/jti/nonce, JWK oct, jkt thumbprint, token bound to key, cannot be replayed without proof, htm/htu binding prevents cross-site replay.

Four-eyes + Continuous Verification

Requester ≠ approver enforced + policy context.requester != approver, state machine requested→approved→executed, attestation re-checked at execution time (continuous verification).

Tamper-evident + Tamper-proof Log

Hash chain prev_hash + entry_hash + HMAC-SHA256 (0600 key separate) + Merkle tree, verify_all, inclusion proof O(log N), SIEM shipping stdout/file + decision_logs + checkpoints.

Strong Credential Storage + MFA

PBKDF2 100k + salt + Argon2id optional (LAB_HASH_ALGO=argon2), timing-safe compare_digest, role whitelist, password strength, TOTP RFC6238 + passkeys, MFA_REQUIRED flag, recovery codes future.

Brute-force & Abuse Defenses

Account locks 15m after 3 fails auto-unlock, IP+user rate limiting 5/min auth, 10/min web, request size limits, velocity and impossible travel risk factors.

CSRF + XSS + Phishing Protection

CSRF tokens per session, SameSite Strict, HttpOnly, html.escape + CSP frame-ancestors none, WebAuthn origin binding prevents phishing.

Detection P4 (23 rules)

6 base rules + risk factors (velocity, impossible travel, device trust, time anomaly, escalation, failed auth, session age) + attestation (emulator, unlocked, old patch, keybox) + webauthn counter clone + DPoP mismatch + tx tamper + policy forbid.

SIEM + Observability

HMAC-keyed logs ship stdout JSON + file, decision logs with policy SHA, Merkle STH + checkpoints, OTEL tracing + Prometheus metrics optional (observability.py).

05

Attacking my own design

An attacker simulation fires six techniques at the running system. All six are detected, producing nine precise alerts (down from fourteen with five false positives before hardening).

AttackHow simulatedDetection rule
Brute force4 wrong passwords for an operatorLOGIN_FAILED count ≥ 3 within 10-min sliding window
Out-of-hoursReset at 03:00RESET_REQUESTED outside 08:00–18:00, outcome created
Privilege escalationOperator tries to approveACCESS_DENIED by policy gate
Unknown deviceRequest reset for AND-999Device ID not in fleet set
ReplaySame request ID twiceOnly the 2nd occurrence is flagged (no double count)
Unapproved executeExecute without approvalRESET_BLOCKED

Tamper demos confirm the defenses: editing a log entry is caught by verification at the exact line (then restored to INTACT), and a self-approval attempt returns APPROVAL_DENIED until a distinct second admin approves.

06

Hardening: P0→P4 Cerberus God Mode

The project was hardened in iterative passes (P0–P4 Cerberus), growing from 18 to 68 tests (52 P2/P3 + 16 P4). Rather than only adding features, I hunted and fixed real security defects, then invented new architecture that even a machine can applaud — Merkle transparency, Cedar ABAC, risk-adaptive, passkeys, StrongBox attestation, WYSIWYS tx signing, DPoP:

  • User enumeration → generic credential messages
  • Timing attacks → hmac.compare_digest
  • Stored/rendered XSS → html.escape + security headers
  • Actor logged as approver instead of executor
  • Shallow-copy fleet mutation (deepcopy fix)
  • Timestamp spoofing in the logger (controlled flag)
  • Password echo → getpass; input validation added

CI enforces the posture: CodeQL, Dependabot, pip-audit, and a TruffleHog secret scan. The work is mapped to MITRE ATT&CK (T1110 brute force, T1078 valid accounts, T1134 privilege escalation, T1070 indicator removal) and NIST 800-53 (IA-5, AC-7, AC-3, AC-5, AU-9, SI-4).

07

Results & takeaways P4

Verified outcomes P4 Cerberus

68 tests pass (52 P2/P3 + 16 P4) on both JSON and SQLite; 6/6 attack categories detected plus 17 new P4 detections (velocity, impossible travel, device trust, attestation, webauthn clone, DPoP, tx tamper); Merkle root verified with inclusion/consistency proofs + Rekor checkpoint anchoring; Cedar policy 10 policies with bundle SHA + AuthZEN; risk-adaptive step-up 30/tx 60/deny 80; passkeys YubiKey 5 + Titan M + Touch ID + StrongBox; attestation Pixel 8 Pro trusted vs Emulator untrusted; WYSIWYS tx signing + DPoP binding; four-eyes cannot be bypassed.

P4 is God Mode: it takes the lab from linear hash chain to Merkle transparency log, from static RBAC to Cedar ABAC with decision logs, from password+MFA to phishing-resistant passkeys + transaction signing, from blind device trust to hardware-backed StrongBox attestation, from bearer tokens to DPoP-bound tokens. This is Zero Trust beyond BeyondCorp — continuous verification, device as trust input, per-session least privilege, assume breach, policy-as-code, short-lived tokens.

08

Limitations & next steps P4

It is still a lab, not an MDM product: Merkle rebuild O(N log N) for simulation (production needs incremental), policy engine is safe AST walk subset of Cedar (production needs Cedar WASM), risk stores in-memory (production needs Redis), WebAuthn/DPoP/TX signing use HMAC sim not real ECDSA/RSA, attestation fleet static JSON not real Android Keystore parsing, TOTP secrets plaintext, HMAC/tx keys file-based not KMS/HSM, SIEM best-effort. 23 honest limitations documented in THREAT_MODEL.md P4 — not hidden.