Skip to content

fix(plugin): clear the adm-zip advisories and the CodeQL maven URL alert - #11

Merged
IronTony merged 2 commits into
mainfrom
fix/plugin-security-alerts
Sep 13, 2026
Merged

IronTony merged 2 commits into
mainfrom
fix/plugin-security-alerts

Conversation

@IronTony

Copy link
Copy Markdown
Owner

Fixes the two findings from a review of the Security tab: CodeQL alert #1 on the Config Plugin's maven repository check, and the adm-zip advisories that appear in npm audit but not on the tab, because Dependabot alerts are off.

Why

  • adm-zip@0.5.17, the only runtime dependency, has GHSA-xcpc-8h2w-3j85 (high, a crafted archive forces an unbounded allocation) and GHSA-vwc7-r8mq-g2x9 (moderate, extraction writes through destination symlinks). Neither is reachable. The plugin never extracts to disk, and it only parses the AAR it downloaded after checking its SHA-256, or its own cached copy under node_modules. Every consumer's npm audit still reports both through this package.
  • CodeQL flags contents.includes(repo) in withDocuSignAndroidMavenRepo as js/incomplete-url-substring-sanitization. The line only prevents a duplicate repository entry, so there is nothing to exploit. The substring match was still wrong: a declaration inside a comment, or a longer URL with the same prefix, counted as present and the repository was never added.

Changes

  • adm-zip goes from ^0.5.17 to ^0.6.1, and @types/adm-zip is removed because 0.6 ships its own types. The 0.6 breaking changes (extractEntryTo path handling, Node 14 minimum) touch nothing the plugin calls.
  • hasMavenRepo reads the string literals in build.gradle, skipping // and /* */ comments, and compares each with the repository URL, trailing slashes removed. Comments and strings are matched in one pass, so a glob like 'libs/*' isn't mistaken for the start of a comment, and backslash escapes are honoured, so "a\"b" doesn't end a string early. Quote style, uri(), trailing comments and multi-line maven blocks still count as declared.
  • First plugin tests in plugin/src/index.test.ts. They run the real projectBuildGradle mod chain from the default export against sample build.gradle content, with no mocks.
  • jest.config.js runs and collects coverage for plugin/src. plugin/tsconfig.build.json excludes *.test.ts, so tests stay out of plugin/build and the tarball. plugin/tsconfig.json still includes them, so the IDE type-checks the test file.
  • CHANGELOG.md entries under ## Next.

Verification

  • 100 Jest tests pass, 15 of them for the plugin. Against the original includes() check, 4 plugin tests fail: line comment, single-line and multi-line block comments, and the longer URL.
  • tsc -p plugin/tsconfig.json (source and test), build, lint, examples type-check and prettier pass. plugin/build holds only index.js, index.d.ts and the source map.
  • npm audit --omit=dev no longer lists adm-zip. 0.6.1 was published by the same npm account as earlier releases, has no dependencies, and matches its GitHub release notes.
  • The plugin's strip sequence ran on 0.6.1 against the real sdk-pdf-2.1.4.aar, whose hash matches SDK_PDF_SHA256. The output passes unzip -t, classes.jar no longer holds the Glide class, and 0.6.1's new duplicate entry and data extent checks don't reject the artifact.
  • Pre-push review ran three times. The first pass found the block comment gap, an overstated SHA-256 claim and an exclusion that did nothing in plugin/tsconfig.json. The second found that an escaped quote earlier on a line hid a declaration, which would have added a duplicate maven block. Both are fixed here. The last pass approved it, with the performance note under follow-ups.

Not verified

  • No expo prebuild and Android Gradle build in a consuming app. The strip check ran the plugin's exact adm-zip calls against the real artifact, not a full prebuild.

Follow-ups

  • Coverage for plugin/src/index.ts reads 49%. The AAR download, strip and cache recovery paths have no tests, and the plugin has no coverage threshold, so the test job is unaffected. Covering them needs fetch and fs mocks.
  • hasMavenRepo searches the whole file, as the old check did, so a matching URL in buildscript.repositories also stops the injection into allprojects.
  • The string matcher is quadratic on one pathological input: a single line of \" pairs with no closing quote takes 2s at 100 KB and 8s at 200 KB. A root build.gradle is a few KB, so it stays a regex. A hand-written linear scanner would remove it.

Notes

  • The CodeQL alert should close when the default setup scan runs on main after merge.
  • Secret scanning is now enabled on the repo. Dependabot alerts stay disabled on purpose.
  • Merge with rebase. The two commits are independent.

adm-zip 0.5.17 is the only runtime dependency and carries two advisories.
GHSA-xcpc-8h2w-3j85 (high) lets an archive that declares a huge uncompressed
size force an unbounded allocation. GHSA-vwc7-r8mq-g2x9 (moderate) lets
extraction write through destination symlinks. Neither is reachable from the
plugin. It never extracts to disk, and it only parses the AAR it downloaded
after checking its SHA-256 against the pin, or its own cached copy under
node_modules. Consumers' npm audit still traced both back to this package.

0.6 ships its own types, so @types/adm-zip goes. Its breaking changes
(extractEntryTo path handling, Node 14 minimum) touch nothing the plugin
calls. The strip was run against the real sdk-pdf-2.1.4.aar on 0.6.1: the
result passes unzip -t and classes.jar no longer holds the Glide class.
withDocuSignAndroidMavenRepo skipped adding the repository whenever
build.gradle contained its URL as a substring. A commented-out declaration or
a longer URL with the same prefix counted as present, so the repository was
never added. CodeQL flagged the same line as
js/incomplete-url-substring-sanitization. The check guards nothing security
related, but the substring match was still wrong.

The check now reads build.gradle's string literals, skipping // and /* */
comments, and compares each with the repository URL, trailing slashes
removed. Comments and strings are matched in one pass, so a glob such as
'libs/*' is not mistaken for the start of a comment, and backslash escapes
are honoured, so an escaped quote does not end a string early. Quote style,
uri(), trailing comments and multi-line maven blocks still count as declared.

The plugin had no tests. Jest now picks up plugin/src, and
plugin/tsconfig.build.json excludes *.test.ts so tests stay out of the
published plugin/build. Coverage now includes the plugin and reports 49% for
plugin/src/index.ts, because the AAR download and strip remain untested. No
threshold is set for it.
@IronTony
IronTony merged commit e0fb8c2 into main Sep 13, 2026
6 checks passed
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