CodeQL documentation

Intent URI permission manipulation

ID: java/android/intent-uri-permission-manipulation
Kind: path-problem
Security severity: 7.8
Severity: error
Precision: high
Tags:
   - security
   - external/cwe/cwe-266
   - external/cwe/cwe-926
Query suites:
   - java-code-scanning.qls
   - java-security-extended.qls
   - java-security-and-quality.qls

Click to see the query in the CodeQL repository

When an Android component expects a result from an Activity, startActivityForResult can be used. The started Activity can then use setResult to return the appropriate data to the calling component.

If an Activity obtains the incoming, user-provided Intent and directly returns it via setResult without any checks, the application may be unintentionally giving arbitrary access to its content providers, even if they are not exported, as long as they are configured with the attribute android:grantUriPermissions="true". This happens because the attacker adds the appropriate URI permission flags to the provided Intent, which take effect once the Intent is reflected back.

Recommendation

Avoid returning user-provided or untrusted Intents via setResult. Use a new Intent instead.

If it is required to use the received Intent, make sure that it does not contain URI permission flags, either by checking them with Intent.getFlags or removing them with Intent.removeFlags.

Example

The following sample contains three examples. In the first example, a user-provided Intent is obtained and directly returned back with setResult, which is dangerous. In the second example, a new Intent is created to safely return the desired data. The third example shows how the obtained Intent can be sanitized by removing dangerous flags before using it to return data to the calling component.

public class IntentUriPermissionManipulation extends Activity {

    // BAD: the user-provided Intent is returned as-is
    public void dangerous() {
        Intent intent = getIntent();
        intent.putExtra("result", "resultData");
        setResult(intent);
    }

    // GOOD: a new Intent is created and returned
    public void safe() {
        Intent intent = new Intent();
        intent.putExtra("result", "resultData");
        setResult(intent);
    }

    // GOOD: the user-provided Intent is sanitized before being returned
    public void sanitized() {
        Intent intent = getIntent();
        intent.putExtra("result", "resultData");
        intent.removeFlags(
                Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
        setResult(intent);
    }
}

References

  • © GitHub, Inc.
  • Terms
  • Privacy