Skip to content

Verify the downloaded Android cmdline-tools archive #485

Description

@potiuk

sdk-installer.ts downloads the Android SDK command-line tools and extracts
them without verifying what came back:

const sdkUrl = isOnMac ? CMDLINE_TOOLS_URL_MAC : CMDLINE_TOOLS_URL_LINUX;
const downloadPath = await tc.downloadTool(sdkUrl);
await tc.extractZip(downloadPath, cmdlineToolsPath);

tc.downloadTool does no integrity checking, so whatever the URL returns is
unzipped onto the runner and added to PATH. The transport is HTTPS to a
Google CDN, which is a reasonable trust anchor, but the archive path itself
(commandlinetools-linux-14742923_latest.zip) is a mutable _latest name -
republishing it changes what every consumer executes, with nothing in the
action able to notice. Both the mac and linux paths are affected.

Why I'm raising it

The ASF is moving its org-wide GitHub Actions allow list from wildcards to
pinned SHAs, and this action is being pinned in
apache/infrastructure-actions#1100. Our review tooling flags this download; it
is the one finding on the action that is not a false positive in our own
checks.

Suggested fix

You already hardcode the build number next to the URL, so pinning a digest
alongside it costs one constant per platform and no new moving parts - hash
the file after downloadTool and fail on mismatch.

A pinned constant in your own source is stronger than fetching a checksum from
the same origin as the archive: it is reviewable in your git history and
bumped deliberately when you bump the build number.

As a cross-check when you do bump, Google publishes per-archive checksums in
the SDK repository manifest at
https://dl.google.com/android/repository/repository2-3.xml - for the build you
currently ship:

<checksum type="sha1">48833c34b761c10cb20bcd16582129395d121b27</checksum>
<url>commandlinetools-linux-14742923_latest.zip</url>

Those are SHA-1 and served from the same origin as the archive, so they are
useful for catching corruption and for deriving the value at bump time, but
are not an independent authenticity signal on their own.

Happy to send a PR if you would like this.


Drafted-by: Claude Opus 5 (1M context) via Claude Code; reviewed by @potiuk before posting

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions