Skip to content

Fix independently-verified findings from a security audit - #7503

Merged
ewels merged 3 commits into
masterfrom
fix-security-audit-findings
Aug 20, 2026
Merged

Fix independently-verified findings from a security audit#7503
ewels merged 3 commits into
masterfrom
fix-security-audit-findings

Conversation

@ewels

@ewels ewels commented Aug 18, 2026

Copy link
Copy Markdown
Member

A security audit of this repo surfaced a handful of latent issues. I reproduced each one independently before touching anything, and only fixed what I could confirm was real.

Why these matter, not just what changed:

  • Nextflow's Docker entrypoint builds a shell command from arbitrary caller-supplied arguments. If that reconstruction isn't airtight, anything able to influence those args (a container invoker, an orchestration layer) can break out of the intended command and run its own — the difference between "runs the pipeline task" and "runs whatever it wants as root inside the container."
  • Debug/trace logging exists so people can troubleshoot connectivity problems, and troubleshooting logs get shared — pasted into tickets, Slack, screen shares — far more casually than anyone treats a credential. A JWT sitting in a trace line means a support workflow doubles as an exfiltration path.
  • Zip extraction that trusts entry names is a well-known class of bug (Zip Slip): a crafted archive can write outside its intended target directory. The code path isn't wired up to anything today, but "nothing calls it yet" is a property of the current codebase, not a property of the function — it's exploitable the moment something does.
  • The Gradle wrapper fetches a distribution over HTTPS but never checked what it got matched what was intended. That's the whole point of pinning a build tool's checksum: it turns "trust the network and the upstream host forever" into "trust it once, verify it every time after."

None of these needed new dependencies or behavior changes — each was a small, targeted correction once confirmed.

A security audit flagged several latent issues; each was independently
reproduced before fixing:

- docker/entry.sh built its command line by hand-wrapping each arg in
  single quotes, then handed the string to `bash -c`. An arg containing
  a single quote breaks out of that quoting into the shell, so any
  caller able to pass through arbitrary Nextflow command-line args
  (e.g. a container invoker) could inject shell commands.
- TowerXAuth logged raw bearer/refresh JWTs at debug/trace level. Those
  levels get enabled during routine troubleshooting, and support logs
  get pasted into tickets/chat more often than anyone would like — the
  tokens shouldn't be there to leak in the first place.
- RemoteSession's zip extraction resolved entry names directly against
  the target directory with no containment check (a classic Zip Slip),
  so a crafted `../../` entry could write outside the target. No
  production caller reaches it today, but the method is reachable and
  the fix is cheap enough that "currently unused" isn't a reason to
  leave it exploitable.
- The Gradle wrapper had no distributionSha256Sum, so a compromised or
  MITM'd services.gradle.org response would be used unverified. Pinned
  after downloading the distribution and independently computing its
  checksum myself, rather than trusting the published hash.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Phil Ewels <phil.ewels@seqera.io>
@netlify

netlify Bot commented Aug 18, 2026

Copy link
Copy Markdown

Deploy Preview for nextflow-docs ready!

Name Link
🔨 Latest commit df929ee
🔍 Latest deploy log https://app.netlify.com/projects/nextflow-docs/deploys/6a86aa9ba345f800089f7efe
😎 Deploy Preview https://deploy-preview-7503--nextflow-docs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Comment thread docker/entry.sh Outdated
Signed-off-by: Phil Ewels <phil.ewels@seqera.io>

@pditommaso pditommaso left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for picking these up — three of the four changes look correct to me. I verified that the pinned distributionSha256Sum matches the published checksum for gradle-9.6.1-bin.zip, and the Zip-Slip guard in RemoteSession is sound (Path.startsWith is element-wise so the /tmp/foo vs /tmp/foobar prefix trap doesn't apply, both sides are normalized, and absolute entry names like /etc/passwd are caught because resolve returns them verbatim). Token redaction in TowerXAuth is good too.

The blocker is docker/entry.sh: as written the %q re-quoting does not close the injection in the NXF_USRMAP branch — I reproduced it locally. Details inline.

Comment thread docker/entry.sh Outdated
Comment thread plugins/nf-tower/src/main/io/seqera/tower/plugin/TowerXAuth.groovy Outdated
Replace the su/bash -c string round-trip with runuser so argv passes
through without a third shell parse, and install util-linux so runuser
is available in the image. Keep refresh response bodies on non-200 only
so failure diagnostics remain without logging JWTs on success.

Assisted-by: Cursor
Signed-off-by: Phil Ewels <phil.ewels@seqera.io>
Co-authored-by: Cursor <cursoragent@cursor.com>
@ewels
ewels merged commit 5400da6 into master Aug 20, 2026
24 checks passed
@ewels
ewels deleted the fix-security-audit-findings branch August 20, 2026 08:02
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.

2 participants