Agent Instructions for AutoRepro Submissions

This document provides quality standards and instructions for creating and modifying AutoRepro proofs-of-concept (PoCs). The primary goal is to produce a high-impact PoC that clearly demonstrates the security impact of a vulnerability.

Guiding Principle: Prove the Security Boundary Crossing

A high-quality PoC must do more than just trigger a bug. It should provide proof that a security boundary has been crossed. To achieve this, all PoCs should follow a three-step “fail-then-succeed” pattern.

The Three-Step Pattern

  1. Setup: Prepare the device and get it into a vulnerable state. This includes installing necessary apps, pushing files, and setting the device to the state it needs to be in just before the exploit is triggered. The setup step can use root to configure the device so long as it‘s justified with inline comments and is a generally accepted state for an end-user’s device to be in.

  2. Prove the Boundary: Before triggering the vulnerability, attempt to perform the target action and assert that the action fails. For example, if the vulnerability allows you to read a protected file, first try to read it and assert that you receive a “Permission Denied” error.

  3. Trigger & Verify: Trigger the vulnerability. Immediately afterward, repeat the exact same action from Step 2 and assert that the action fails on a patched device. This provides clear proof that your exploit has bypassed the security boundary. A vulnerable device should fail the test because the trigger action passed.

The Final Assertion

The final assertion in Step 3 is the most important part of the test. It must be clear, descriptive, and contain the proof of the exploit.

The final assertion message (for a vulnerable device) should include the captured artifact as proof when possible.

The assertion message must begin with the exact prefix AUTOREPRO_VULNERABILITY_PROVEN:. The message following the prefix must contain a concise description of the vulnerability and include any captured artifacts (e.g., leaked data, error codes, unexpected state) that prove the exploit was successful.

Good Example:

// Step 3: Trigger the vulnerability, then read the file again.
try {
  String fileContent = readFile("/data/data/com.victim.app/files/secret.txt");
  // The test fails because the device is vulnerable, and the failure message
  // contains the proof (the content of the secret file).
  Assert.fail("AUTOREPRO_VULNERABILITY_PROVEN: Successfully read protected file. Content: '" + fileContent + "'");
} catch (ThisVulnSpecificException e) {
  Log.i(TAG, "protected against reading protected file", e);
}

By following this pattern, the resulting test provides a clear, verifiable, and high-impact demonstration of the vulnerability.

Style Guidelines

  • It's helpful if the test code is annotated with comments explaining why certain steps work.
  • Tests should be non-interactive and avoid manual steps or manual UI interaction.
  • UI interaction can be driven with uiautomator.
  • Avoid Thread.sleep() for synchronization.

How to Run Tests Manually

The recommended way to run tests is using the pre-configured Android Studio run configurations (e.g., autorepro_nonroot_arm64).

To run the tests from the command line, you must replicate the steps found in the .run/*.run.xml files. These XML files define the two-stage process for running a test:

  1. The Build Step: Look for a “BeforeRunTask” that executes a Gradle command. This command is responsible for compiling all the code and assembling the necessary test artifacts.

  2. The Execution Step: After the build, the configuration defines the main command that invokes the test harness (e.g., Tradefed) and runs the actual test suite. You will need to identify the executable and the program parameters being passed to it.

By inspecting the XML, you can extract these two commands to run the full test process from your terminal.