Skip to content

Enforce testcase-level access control for testcase blob downloads in /download#5297

Open
evilgensec wants to merge 2 commits into
google:masterfrom
evilgensec:fix-download-testcase-access-control
Open

Enforce testcase-level access control for testcase blob downloads in /download#5297
evilgensec wants to merge 2 commits into
google:masterfrom
evilgensec:fix-download-testcase-access-control

Conversation

@evilgensec
Copy link
Copy Markdown

@evilgensec evilgensec commented May 29, 2026

Summary

handlers/download.py serves testcase-scoped blobs (a testcase's minimized/fuzzed reproducer) after only the general access.has_access() check, consulting the testcase-level access.can_user_access_testcase() check only as a fallback:

if access.has_access():
    return self._send_blob(...)
if not testcase:
    raise helpers.AccessDeniedError()
if access.can_user_access_testcase(testcase):   # only reached if has_access() was false
    return self._send_blob(...)

The sibling handlers that serve the same testcase blobs gate testcase content on can_user_access_testcase() first:

  • handlers/viewer.pyif testcase_id: if not access.can_user_access_testcase(testcase): raise AccessDeniedError(); has_access() is used only for non-testcase content.
  • handlers/testcase_detail/download_testcase.pyaccess.check_access_and_get_testcase(testcase_id).

can_user_access_testcase() escalates to privileged access for security testcases (need_privileged_access = testcase.security_flag and not config.relax_security_bug_restrictions), whereas has_access() (get_access(need_privileged_access=False)) also returns Allowed for any whitelisted_domains user. As a result, on /download a user with general access but without testcase-level access can download a testcase reproducer they are not permitted to view via /viewer.

Change

Gate testcase-scoped blobs on can_user_access_testcase() before the general has_access() check, matching viewer.py; retain has_access() for non-testcase blobs. Privileged users, the testcase uploader, and associated-bug participants are unaffected (they pass can_user_access_testcase()); domain-allowed users keep access to non-security testcases. The public OSS-Fuzz path (check_public_testcase) is unchanged and runs earlier.

handlers/download_test.py's test_download_user is updated to assert the corrected behavior: general access alone grants non-testcase blobs, and testcase blobs require testcase-level access.

Note: the full handler suite was not run locally (it requires the datastore emulator); the change is a structural alignment with viewer.py and the test mirrors existing patterns in the file.

@evilgensec evilgensec requested a review from a team as a code owner May 29, 2026 09:43
@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 29, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

…/download

The /download handler gated testcase-scoped blobs on the general
access.has_access() check, using the testcase-level
access.can_user_access_testcase() check only as a fallback. The sibling
handlers serving the same blobs (viewer.py and
testcase_detail/download_testcase.py) gate testcase content on
can_user_access_testcase() first, which enforces the privileged-access
requirement for security testcases (testcase.security_flag). As a result, a
user with general access but without testcase-level access could download a
testcase reproducer they are not permitted to view via /viewer.

Gate testcase-scoped blobs on can_user_access_testcase() before the general
access.has_access() check, matching viewer.py; retain has_access() for
non-testcase blobs. Update the handler test accordingly.
@evilgensec evilgensec force-pushed the fix-download-testcase-access-control branch from e4bdc7b to 39f7814 Compare May 29, 2026 09:50
crash_query returned a matching testcase id and bug id for any authenticated user, without the security_flag-aware scoping the sibling query handlers apply, so a non-privileged user supplying a matching stacktrace could confirm the existence of and read the testcase/bug id of a security-confidential testcase. Suppress the duplicate when it is security_flag and the caller cannot access it, using the same can_user_access_testcase check the per-testcase handlers use.
@evilgensec evilgensec force-pushed the fix-download-testcase-access-control branch from 5522561 to c9b8ff1 Compare May 30, 2026 04:55
@evilgensec
Copy link
Copy Markdown
Author

Added a second commit that applies the same security_flag-aware scoping to the /crash-query duplicate-detection handler (crash_query.py): it returned a matching testcase's id and bug id to any authenticated user, without the crash_access.add_scope/can_user_access_testcase check the sibling query and per-testcase handlers use. The handler now suppresses a security-confidential duplicate when the caller cannot access it, with a regression test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant